react-hook-form with formatted numeric values

I have an "amount" field which is numeric in my react-hook-form. Since the amounts can grow up to the millions in my case, I want to format the displayed value having a thousand separator for better UX. I looked for libs for formatting these values, and the best (maintained, easy to use, high popularity) I could find was react-number-format, so I gave it a shot. I found some attempts, all telling I might need to make my input "uncontrolled". These are the 2 ways I tried: https://stackoverflow.com/a/69258165/3045531 https://stackoverflow.com/a/63091512/3045531 My problem is that the actual form value linked to the field in the form's context is not numeric but a string, since it's handling the formatted value there, not the numeric one. How can I make the form handle the numeric value instead of the formatted one, so my Zod validation won't fail there? I would prefer not to use coerce in the schema to keep it cleaner.
Stack Overflow
How do I integrate React hook form with NumberFormat (react-number-...
I am trying to use React hook form with NumberFormat without Controller and without ReactDOM.findDOMNode (which is deprecated and discouraged). The following code works import React from 'react'; i...
Stack Overflow
Thousand separator input with React Hooks
I would like to add on a input a thousand separator using React Hooks but I'm not sure how. I have tried the below code so far and is not working. Can you please point out what could be the issue a...
18 Replies
Brendonovich
Brendonovich•17mo ago
If you do use react-number-format, you can use the onValueChange callback to get the floatValue and pass that to the onChange from Controller/useController
froxx
froxx•17mo ago
Tried that. Still results in string values:
const NumberInput = (props) => {
const { name } = props;

const form = useFormContext();

// always logs string values
console.log(form.getValues(name));

return (
<Controller
{...{
control: form.control,
name,
render: ({ field: { value, onChange } }) => (
<NumericFormat
{...{ value, onChange }}
onValueChange={({ floatValue }) => {
form.setValue(name, floatValue);
}}
thousandSeparator=","
/>
),
}}
/>
);
};
const NumberInput = (props) => {
const { name } = props;

const form = useFormContext();

// always logs string values
console.log(form.getValues(name));

return (
<Controller
{...{
control: form.control,
name,
render: ({ field: { value, onChange } }) => (
<NumericFormat
{...{ value, onChange }}
onValueChange={({ floatValue }) => {
form.setValue(name, floatValue);
}}
thousandSeparator=","
/>
),
}}
/>
);
};
Brendonovich
Brendonovich•17mo ago
Possibly because you're passing both onChange and onValueChange, try calling onChange within onValueChange instead of using setValue
froxx
froxx•17mo ago
Oh. I tried that before, but also passed onChange to <NumericFormat /> as well just as I did with value. So it probably worked for a moment, but got overwritten instantly. After only passing value and calling onChange within onValueChange that works! Anyway there are still some more problems due to the input being controlled here: - It doesn't respond to a <button type="reset" /> - RHF doesn't auto focus the field after a failed validation - I'd like to hand in my standard input component as customInput to NumericFormat, but since that one is uncontrolled as well, it throws some issues Is there no way to do the formatting in an uncontrolled state?
Brendonovich
Brendonovich•17mo ago
for point 3 i can say that customInput likely isn't designed for uncontrolled inputs, you'll have to make a custom one out of divs or something For 2 you need to pass field.ref to the component so that it can focus Point 3 i'm not quite sure since the value should get reset internally and propagated on rerender
Finn
Finn•17mo ago
Brendon when he sees a post about forms todd
Brendonovich
Brendonovich•17mo ago
yeah i'm kinda the form guy now
froxx
froxx•17mo ago
Helped me a lot in my last question, so I appreciate it 😄
Brendonovich
Brendonovich•17mo ago
👀
Finn
Finn•17mo ago
😩😩😩
Brendonovich
Brendonovich•17mo ago
make a stackblitz with a basic example and i'll take a look at point 3
froxx
froxx•17mo ago
I tried that but can't figure out how to actually pass the ref there since it's a functional component, and React doesn't like that
Brendonovich
Brendonovich•17mo ago
forwardRef assuming that's what u mean
froxx
froxx•17mo ago
Yeah, I read that in the error message as well, but I don't know how React wants to get that there. I tried this, but it doesn't like it:
<Controller
{...{
control: form.control,
name,
render: ({ field: { value, onChange, ref } }) =>
// eslint-disable-next-line react/display-name
React.forwardRef(() => (
<NumericFormat
{...{ value, ref }}
onValueChange={({ floatValue }) => {
onChange(floatValue);
}}
thousandSeparator=","
<Controller
{...{
control: form.control,
name,
render: ({ field: { value, onChange, ref } }) =>
// eslint-disable-next-line react/display-name
React.forwardRef(() => (
<NumericFormat
{...{ value, ref }}
onValueChange={({ floatValue }) => {
onChange(floatValue);
}}
thousandSeparator=","
I don't really know a lot about refs until this point poohheh taking the 2nd parameter from forwardsRef instead of the one from Controller.render doesn't solve it
Brendonovich
Brendonovich•17mo ago
try passing ref to getInputRef no need for forwardRef
froxx
froxx•17mo ago
Ah. That makes sense Well I guess I could go for the controlled number inputs for now. I'm not too happy since the simple "add register(name) to it, and everything works fine in the context"-way of RHF is really handy. Anyway, I get my formatted value this way, my validation works, and those are the main points. Taking care of a working reset functionality etc can be seen as "sugar" for the future. So thanks again to you, @Brendonovich , lord of the forms ✨
Brendonovich
Brendonovich•17mo ago
yeah for a use case like this you pretty much cannot use uncontrolled inputs, since with uncontrolled inputs the value is derived from the text. glad i could help! also i'd recommend using useController over Controller
froxx
froxx•17mo ago
True. Hooks are nice. Thanks
Want results from more Discord servers?
Add your server
More Posts
How well can I rely on Tailwinds ability to know what classes to include in the CSS?I'm new to Tailwind and I'm trying to understand how it works under the hood. More specifically howtips on getting file sizes down in a nextjs 13 project?things are getting preeeeetttyyyyy heftyyyy in my big project ```json // package.json "dependenciWhat's everyone using for implementing google sso?We have a vite app where we manage user sessions in a django backend - need to replace react-google-What is an effective way to proxy your backend API? (NextJS)Currently all my queries go through the client server which calls my backend API. It seems a bit ineNext Font showing ts errorsmy next font is showing typescript errors, it seems to be used how they do it in the docs. Any ideaswrapping a generic function in typescripti'm trying to write a wrapper to automatically handle loading state when necessary. my idea is to wris it problem to install next-auth by hand?while I was installing t3-app i didnt have in my mind to use next-auth and then realized i have to uDocker & Nginx - portsHi, I am running Docker containers on my VPS and I'd like to deploy there an API with Nginx config. Does React Context/Providers inherently cause lower perf or only if it reloads a lot of components?I'm creating a Switch component and want to pass the `enabled` state to the thumb component via a PrUsing CASL with the T3 StackLook at https://github.com/stalniy/casl it seems quite cool, is it just a case of following the Pris