In this code, I have the value 1000000 (one million) which I format with toLocaleString('en-gb')
to get 1,000,000
.
Then I print that value as text and it works as expected, also when I use that const as the value of a text input. But when using the value in a numeric input, it just doesn't render. It works though when the value is < 1 million.
Inspecting the html, I see the value is correct:
In addition, when trying to type the value in that numeric input, it doesn't register values after 4 digits.
Any ideas what's going on? I wonder if it could be that after 999.000 the number will have two thousand-separators
teh codez (also in this playground https://stackblitz.com/edit/react-ts-8ufbe1?file=App.tsx):
export default function App() {
const value = (1000000).toLocaleString('en-gb');
const [inputValue, setInputValue] = React.useState(value);
return (
<div>
<h1>{value}</h1>
<input
type="number"
value={inputValue}
onChange={(e) => setInputValue(Number(e.target.value).toLocaleString('en-gb'))}
/>
<input type="text" value={inputValue} />
</div>
);
}
I see there are libraries like react-number-format but seems like the native way should do what I need.
Thank you very much in advance.
It works before reaching 1,000 because 1,000 is where you have to add a comma. At 999 you still satisfy the requirements of an input with type number you're inserting only a number 999
. Since HTML only really allows strings they let you pass with "999"
vs 999
the pure numeric version.
In any case. I don't think you want to use the type='number'
it works pretty poorly and shows the ticker up and down. If this is a mobile focused decision consider using type='tel'
.
What you can also do is attempt to manually mask the behavior by putting 2 inputs on top of each other. Or you can use an input type='tel' onFocus={() => Number(inputValue)}
and onBlur={() => inputValue.toLocaleString('en-gb')}
and that will be the start to getting where you want to get.
This type of stuff usually is slightly messy and will take a bit to perfect. The UI can easily get wonky, and the problem is not so perfectly solved:
If you don't want to directly import a library which contains this I'd strongly suggest you read their source code.
Some potential resources: https://cchanxzy.github.io/react-currency-input-field/ (Note that just the single component is 600 lines long)
including this excerpt:
const handleOnFocus = (event: React.FocusEvent<HTMLInputElement>): number => {
onFocus && onFocus(event);
return stateValue ? stateValue.length : 0;
};
/**
* Handle blur event
*
* Format value by padding/trimming decimals if required by
*/
const handleOnBlur = (event: React.FocusEvent<HTMLInputElement>): void => {
const {
target: { value },
} = event;
const valueOnly = cleanValue({ value, ...cleanValueOptions });
if (valueOnly === '-' || !valueOnly) {
setStateValue('');
onBlur && onBlur(event);
return;
}
const fixedDecimals = fixedDecimalValue(valueOnly, decimalSeparator, fixedDecimalLength);
const newValue = padTrimValue(
fixedDecimals,
decimalSeparator,
decimalScale !== undefined ? decimalScale : fixedDecimalLength
);
const numberValue = parseFloat(newValue.replace(decimalSeparator, '.'));
const formattedValue = formatValue({
...formatValueOptions,
value: newValue,
});
if (onValueChange) {
onValueChange(newValue, name, {
float: numberValue,
formatted: formattedValue,
value: newValue,
});
}
setStateValue(formattedValue);
onBlur && onBlur(event);
};
```