Created
December 27, 2025 18:52
-
-
Save oleg1994/566c47caa4c447509328ce7814d837ab to your computer and use it in GitHub Desktop.
format number as currency while typing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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