Home > Software engineering >  Set focus on react component from onBlur
Set focus on react component from onBlur

Time:08-17

We have an input field that's a react component (based on MUI TextField). We want to validate the input when the user leaves the field and, if it's incorrect, set the focus back to that field. Currently the component is set up like this:

<TextBox
  className="phone-data"
  value={phone}
  onChange={(e) => setPhone(e.target.value)}
  onBlur={() => {
    if (!validatePhone(phone)) {
      alert('Phone number is not valid')
      setPhone('');
    }
  }}>
</TextBox>

The TextBox component is defined like this:

const TextBox = ({ className, label, onChange, type, value, width, onBlur, children }) => {
  return (
    <TextField
      sx={{
        '& .MuiOutlinedInput-root': {
          '& > fieldset': { borderColor: 'gray' },
        },
        'minWidth': width,
        'bgcolor': '#1a1a1a',
      }}
      variant="outlined"
      size="small"
      className={className}
      type={type}
      label={label}
      onChange={onChange}
      onBlur={onBlur}
      value={value}
    >
      {children}
    </TextField>
  );
};

After the setPhone('') call in the onBlur handler of TextBox, we want the focus to stay on the TextBox, and not go to whatever the user clicked on. From what we've found so far it seems to have something to do with refs, but ref is not a field of MUI TextField. Thanks.

CodePudding user response:

you need to first change your TextBox component to have ref like this:

const TextBox = React.forwardRef(({ className, label, onChange, type, value, width, onBlur, children },ref) => {
  return (
    <TextField
      ref={ref}
      sx={{
        '& .MuiOutlinedInput-root': {
          '& > fieldset': { borderColor: 'gray' },
        },
        'minWidth': width,
        'bgcolor': '#1a1a1a',
      }}
      variant="outlined"
      size="small"
      className={className}
      type={type}
      label={label}
      onChange={onChange}
      onBlur={onBlur}
      value={value}
    >
      {children}
    </TextField>
  );
});

and then you need to change the call of the component as this:

const textBoxRef = useRef();

<TextBox
  className="phone-data"
  ref={textBoxRef}
  value={phone}
  onChange={(e) => setPhone(e.target.value)}
  onBlur={() => {
    if (!validatePhone(phone)) {
      alert('Phone number is not valid')
      setPhone('');
      textBoxRef.current.focus();
    }
  }}>
</TextBox>

CodePudding user response:

In functional components, you need to use React.forwardRef. Similar to how we could tap into HTMLElement's DOM properties using ref, we can also create ref property for higher order components such as your TextBox component, by forwarding the ref.

I've created a minimalist example similar to your without bells and whistles. Check this out. https://codesandbox.io/embed/epic-panini-wmy9zu

For complete documentation, check this from React site. It would prove to be useful. https://reactjs.org/docs/forwarding-refs.html

  • Related