Search code examples
javascriptreactjsformsfocusonchange

How to change a class based on focus and change in an input form in React


I have a situation where I want to append a class called shrink to the label text below (Display Name) when I click or type in the input box. My code is below:

const FormInput = ({ label, ...otherProps} ) => {
    let labelClassName = 'formInput-label';

    const addLabelClassName = () => {
        labelClassName = `${labelClassName} shrink`;
        console.log(labelClassName, 'labelClassName inside')
    }

    console.log(labelClassName, 'labelClassName outside')

    return (
        <div className="group">
            {label && 
                <label 
                    className={labelClassName}
                >{label}</label>
            }
            <input onFocus={addLabelClassName } onChange={addLabelClassName } className="formInput" {...otherProps} />
        </div>
    )
};

My question:

  1. Why does when I focus/ type, at first, React outputs the correct classnames for labelClassName inside as formInput-label shrink, but immediately changes it back to formInput-label at the labelClassName outside position? How would I fix this?

  2. I have also tried to change the code to using the UseState approach like below:

const FormInput = ({ label, ...otherProps} ) => {
    const [interaction, setInteraction] = useState('');
    let labelClassName = 'formInput-label';

    const onInteracting = () => {
        setInteraction('interacting')
    }

    if(interaction === 'interacting') {
        labelClassName = `${labelClassName} shrink`;
    }

    return (
        <div className="group">
            {label && 
                <label 
                    className={labelClassName}
                >{label}</label>
            }
            <input onFocus={onInteracting} onChange={onInteracting} className="formInput" {...otherProps} />
        </div>
    )
};

And this will append the correct class shrink to labelClassName but I'm not able to take that off when I click outside of the input/form. How may I fix this?

Thank you a ton!


Solution

  • The second approach is a better way because with changing state you will trigger component rerendering (the first approach will never re-render component).

    In the second approach, you can take advantage of onBlur event and create a handler which will set the state to the default value. Something like this. You don't need onChange to setIntercation

    ...
     const handleBlur = () => {
        setInteraction("");
      };
    ...
    

    and then in input, you have to set up onBlur prop. onChange should not do the same thing as onFocus already does.

    ....
     <input
            onFocus={onInteracting}
            onBlur={handleBlur}
            className="formInput"
            {...otherProps}
          />
     ....