Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextInput Label doesn't shrink when filling from inputRef #17018

Closed
2 tasks done
minhaferzz opened this issue Aug 15, 2019 · 36 comments
Closed
2 tasks done

TextInput Label doesn't shrink when filling from inputRef #17018

minhaferzz opened this issue Aug 15, 2019 · 36 comments
Labels
component: text field This is the name of the generic UI component, not the React module!

Comments

@minhaferzz
Copy link

When I'm using react-hook-form to set some values in a TextInput I receive from the server, it populates correctly, but doesn't shrink the label.

  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

Currently the text is overlapping the placeholder text.

Expected Behavior 🤔

The placeholder should shrink and display above the filled text.

Steps to Reproduce 🕹

https://codesandbox.io/s/react-hook-form-mui-textfield-3czpw

Context 🔦

This started happening in v4.2.1 and up. It works in v4.2.0.

@oliviertassinari
Copy link
Member

Are you sure about the reproduction? I don't see any issue.

@minhaferzz
Copy link
Author

@oliviertassinari Yes, I might have forgotten to save the code the codesandbox. Please check it again. The placeholder is overlapping the text.

@oliviertassinari
Copy link
Member

Could the problem come from #16526?

@oliviertassinari oliviertassinari added the component: text field This is the name of the generic UI component, not the React module! label Aug 16, 2019
@erfan226

This comment has been minimized.

@eps1lon
Copy link
Member

eps1lon commented Aug 20, 2019

I don't understand why that library needs to mutate the value in the DOM instead of using defaultValue on the <input />. Could you verify that it cannot work with defaultValue being specified on the element?

Using defaultValue should automatically cause the filled state and we don't need extra effect handling.

@erfan226

This comment has been minimized.

@oliviertassinari

This comment has been minimized.

@bluebill1049
Copy link

hi @eps1lon, Yes you can set defaultValue on the input and it should work. However, this library is leveraging some of the goodies from the uncontrolled component, which means when we declare defaultValues in the custom hook.

eg: useForm({ defaultValues: { test: '123' } })

This library itself have to mutate the input value. hope this makes sense, I would love to make this lib compatible with material-ui, as myself is a big fang of MUI. let me know if things I can improve to make integration easier, or even how things should be done in usage so I can document on the website.

@eps1lon
Copy link
Member

eps1lon commented Aug 21, 2019

However, this library is leveraging some of the goodies from the uncontrolled component, which means when we declare defaultValues in the custom hook.

defaultValue as a prop is for uncontrolled components. Why is this not sufficient and requires mutating the instance?

@bluebill1049
Copy link

bluebill1049 commented Aug 21, 2019

defaultValue as a prop is for uncontrolled components. Why is this not sufficient and requires mutating the instance?

It's more of a DX thing, like I mentioned above when dev wants to declare all default values in one go. The library allows them to write things like

const { register } = useForm({
  defaultValues: {
    firstName: "bill",
    lastName: "luo",
    email: "bluebill1049@hotmail.com",
    pets: [ 'dog', 'cat' ]
  }
})

<input name="firstName" ref={register} />

during register the input mutation will happen.

@eps1lon
Copy link
Member

eps1lon commented Aug 21, 2019

But why do you need to go outside of react to change the value? We already have all the tools in place to solve these issues. We specifically want to avoid mutating the instance from outside because this can cause all sorts of unforeseen issues. Especially when you're building a brand new library using hooks there's really no need to go back to handling state via DOM.

If your concern is DX you could just as well use const props = useForm(); <input {...props} /> where props = { value, ref }. This seems like you just want it to look faster because render counts don't change.

@eps1lon
Copy link
Member

eps1lon commented Aug 21, 2019

The more I look at this the more I feel like using defaultValue as a prop is even better for DX. Your example has an indirection between the input name and its default value. One has to look at the component, check the name, look at the hook, scan for the key with the name and then sees the default value.

By having name and defaultValue at the component I have those next to each other and eliminate potential bugs when mispelling/renaming names or keys.

@bluebill1049
Copy link

First of all, thanks for the feedback :)

We specifically want to avoid mutating the instance from outside because this can cause all sorts of unforeseen issues.

In this instance, I couldn't see an issue when setting up the default value. It leverages the native DOM API and it's not "outside" (it using component ref).

This seems like you just want it to look faster because render counts don't change.

I disagree with the above statement, it's not the intention for this library to "look" faster. The intention is great DX and better performance (it can be). I don't want to go for syntax like <input {...props} /> which I don't want to go into such discussion.

I guess the solution right now is to trigger an extra re-render when user changing defualtValue, I am happy to document it down in the website, so users do aware. thanks for looking into this issue tho.

@bluebill1049
Copy link

By having name and defaultValue at the component I have those next to each other and eliminate potential bugs when mispelling/renaming names or keys.

Totally agree, one of the reasons we had typescript support to declare a type, so avoid misspell the name.

@eps1lon
Copy link
Member

eps1lon commented Aug 21, 2019

I don't want to go for syntax like <input {...props} /> which I don't want to go into such discussion.

Well I'm happy to hear your reasoning but if you don't want to discuss this we can close the issue. I'll wait a bit in case someone else has other arguments.

The intention is great DX and better performance (it can be).

Could you share some benchmarks so that we can evaluate if it would make sense to support this API?

Totally agree, one of the reasons we had typescript support to declare a type, so avoid misspell the name.

This sounds interesting. How do you make sure I can't write const { register } = useForm({ defaultValues: { bar: 'baz' } }); <input name="foo" ref={register} />;?

@bluebill1049
Copy link

Well I'm happy to hear your reasoning but if you don't want to discuss this we can close the issue. I'll wait a bit in case someone else has other arguments.

It's a design decision which I made when I start building react hook form. I prefer things to be more declarative so devs can see each prop. Not a big fan of {...props} you need to overwrite or get overwritten by what's in the ...props.

The intention is great DX and better performance (it can be).

sure, do you mean overall performance enhancement of this library or just setting up defaultValue? When I made my statement above, I meant overall. If you are interested in terms of overall performance enhancement, I have a couple of screenshot on the website: https://react-hook-form.com

This sounds interesting. How do you make sure I can't write const { register } = useForm({ defaultValues: { bar: 'baz' } }); ;?

export interface Props<Data extends DataType> {
  mode?: Mode;
  defaultValues?: Partial<Data>;
  nativeValidation?: boolean;
  validationFields?: (keyof Data)[];
  validationSchema?: any;
  submitFocusError?: boolean;
}

This is what we have at the moment, this library is still very young and we are still consistently improving on the type and everything else. I don't think we can prevent everything but at least we try :)

By the way, my intention was not to ask MUI to make a change for react-hook-form, rather than find a solution in between.

@minhaferzz
Copy link
Author

Would defaultValue handle a case where I would need to load a value from a server and set the default value at that time?

@bluebill1049
Copy link

@minhaferzz no :(

@oliviertassinari oliviertassinari added the out of scope The problem looks valid but we won't fix it (maybe we will revisit it in the future) label Aug 23, 2019
@oliviertassinari
Copy link
Member

I'm closing, following #17025 (comment). @bluebill1049 let us know if you see more people facing this issue, we could revaluate in the future.

@bluebill1049
Copy link

Thanks @oliviertassinari and @eps1lon anyhow for looking into this.

@sdornan
Copy link
Contributor

sdornan commented Mar 2, 2020

I'm having a similar issue as this, but it's unclear if it's the same or different. I'm using setValue() on a few Material UI input fields on page load, but the labels are not shrinking properly in Safari only. In Chrome, the MuiInputLabel-shrink and MuiInputLabel-filled classes are being properly applied. Let me know if I should open a separate issue, or if it's a Material UI problem and I should open an issue there.

image

image

@oliviertassinari oliviertassinari removed the out of scope The problem looks valid but we won't fix it (maybe we will revisit it in the future) label Mar 2, 2020
@oliviertassinari
Copy link
Member

@sdornan If you have a minimal live reproduction that show that the issue originates from Material-UI, e.g. using codesandbox, feel free to open a new issue. In the case of react-hook-form, we have already explored some of the issues with the approach the library took. More details in #18269 (comment).

@bluebill1049
Copy link

@sdornan please consider using Controller with MUI components.
https://react-hook-form.com/api#Controller

@sdornan
Copy link
Contributor

sdornan commented Mar 2, 2020

Here's a reproduction: https://codesandbox.io/s/hopeful-mountain-cgx6p

Will open a new issue if necessary.

@gradinarot
Copy link

@sdornan did you got this resolved?

@bluebill1049
Copy link

@gradinarot
Copy link

I manged to solve it by passing InputLabelProps and biding the "shrink" prop to the field's value.

@rfoel
Copy link

rfoel commented May 13, 2020

@bluebill1049 Using Controller does not work on Safari either.

@bluebill1049
Copy link

@rfoel I don't think so. Provide a code sandbox and screenshots/video.

@sdornan
Copy link
Contributor

sdornan commented May 14, 2020

@gradinarot I did the same thing as you.

@Shaka-60hp
Copy link

I manged to solve it by passing InputLabelProps and biding the "shrink" prop to the field's value.

I know this is old, but how did you do it? passing state value and useEffect? ... I'm working in the same direction

@bluebill1049
Copy link

I manged to solve it by passing InputLabelProps and biding the "shrink" prop to the field's value.

I know this is old, but how did you do it? passing state value and useEffect? ... I'm working in the same direction

Read the documentation.

https://react-hook-form.com/api/usecontroller/controller

CSB: https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5

@levyal
Copy link

levyal commented Jan 4, 2022

I manged to solve it by passing InputLabelProps and biding the "shrink" prop to the field's value.

I know this is old, but how did you do it? passing state value and useEffect? ... I'm working in the same direction

Put something like this on your TextField.

InputLabelProps={{
shrink: controllerProps.value ? true : false
}}

@Asghwor
Copy link

Asghwor commented Apr 11, 2022

@gradinarot https://react-hook-form.com/api#Controller

@bluebill1049, I know this is an old thread, but is there a way to solve this issue without the controller?

TextField stutters with the controlled input, so it would be great if there was a way, even if hacky, to make the components' labels shrink back.

@dimitriBouteille
Copy link

I had the same problem, here’s how I fixed the bug 🥳

import {Controller} from "react-hook-form";
import {TextField} from "@mui/material";
import Cleave from "cleave.js/react";
import React from 'react'
import 'cleave.js/dist/addons/cleave-phone.fr'

const CleaveTextField = React.forwardRef((props, ref) => (
    <Cleave htmlRef={ref} {...props} />
));


/**
 * @param name
 * @param control
 * @param label
 * @param required
 * @returns {JSX.Element}
 * @constructor
 */
const PhoneField = ({ name, control, label, required }) => {

    return (
        <Controller
            name={name}
            control={control}
            render={({ field, formState,}) => {
                const errorMessage = formState.errors[name]?.message || '';
                return <TextField
                    {...field}
                    label={label}
                    error={!!errorMessage}
                    helperText={errorMessage as string}
                    fullWidth
                    placeholder='00 00 00 00 00'
                    required={required}
                    InputProps={{
                        inputComponent: CleaveTextField
                    }}
                    inputProps={{
                        options: {
                            phone: true,
                            phoneRegionCode: 'FR',
                        }
                    }} />
            }} />
    );
};

export default PhoneField;

@WahidSaeed
Copy link

The Label Shrinks if you wrap the input component with Controller and pass the value into it.

<Controller control={control} name="name"
   rules={{
     required: true,
   }}
   render={({ field: { value } }) => (
     <TextField
         onChange={(x) => setValue("name", x.currentTarget.value)}
         value={value}
         id="name"
         label="Name"
         variant="standard"
         fullWidth
     />
   )}
/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: text field This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging a pull request may close this issue.