Skip to content

Instantly share code, notes, and snippets.

@oleg1994
Created December 27, 2025 18:52
Show Gist options
  • Select an option

  • Save oleg1994/566c47caa4c447509328ce7814d837ab to your computer and use it in GitHub Desktop.

Select an option

Save oleg1994/566c47caa4c447509328ce7814d837ab to your computer and use it in GitHub Desktop.
format number as currency while typing
import React from "react";
import { StyleSheet, TextInput } from "react-native";
import { SafeAreaView, SafeAreaProvider } from "react-native-safe-area-context";
/**
* Formats a text input as currency-like text while typing.
* - Keeps only digits + one dot
* - Allows ".5" -> "0.5"
* - Limits decimals to 2
* - Adds thousands separators to the integer part
* - If the user tries something invalid (like a 2nd dot), it keeps the previous value
*/
const formatAsCurrency = (nextText, prevValue = "") => {
// Keep only digits and dots
let text = String(nextText ?? "").replace(/[^\d.]/g, "");
// Empty is valid
if (text === "") return { value: "" };
// Only one dot allowed — if more, ignore this change (keep previous)
const dotCount = (text.match(/\./g) || []).length;
if (dotCount > 1) return { value: prevValue };
// If it starts with dot, normalize: ".5" -> "0.5"
if (text.startsWith(".")) text = `0${text}`;
// Optional: remove leading zeros for integers like "00012" -> "12"
// but keep "0" and "0.x"
if (text.length > 1 && text[0] === "0" && text[1] !== ".") {
text = text.replace(/^0+/, "");
if (text === "") text = "0";
}
// Split integer/decimal
const dotIndex = text.indexOf(".");
let intPart = dotIndex === -1 ? text : text.slice(0, dotIndex);
let decPart = dotIndex === -1 ? "" : text.slice(dotIndex + 1);
// Limit decimals to 2
if (decPart.length > 2) decPart = decPart.slice(0, 2);
// Add commas to integer part (remove existing commas just in case)
intPart = intPart.replace(/,/g, "");
intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
// Rebuild
const value = dotIndex === -1 ? intPart : `${intPart}.${decPart}`;
return { value };
};
const TextInputExample = () => {
const [price, setPrice] = React.useState("");
const [number, onChangeNumber] = React.useState("");
return (
<SafeAreaProvider>
<SafeAreaView>
<TextInput
style={styles.input}
value={price}
onChangeText={(val) => {
const res = formatAsCurrency(val, price);
setPrice(res.value);
}}
placeholder="Price"
keyboardType="decimal-pad"
/>
<TextInput
style={styles.input}
onChangeText={onChangeNumber}
value={number}
placeholder="Other input"
keyboardType="numeric"
/>
</SafeAreaView>
</SafeAreaProvider>
);
};
const styles = StyleSheet.create({
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
});
export default TextInputExample;
const toBackendAmount = (formattedValue) => {
if (!formattedValue) return null;
return Number(formattedValue.replace(/,/g, ""));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment