how do i focus an input in react form for form validation

4.9k Views Asked by At

So I've coded this react small react form specifically for this question and I want to add a feature to it.

Here's the code:

import React, { useState } from "react";

export default function App() {
  const [formInfo, setFormInfo] = useState({ name: "", email: "" });

  function onch(e) {
    const { value, id } = e.target;

    id === "name"
      ? setFormInfo({ ...formInfo, name: value })
      : setFormInfo({ ...setFormInfo, email: value });
  }

  function onsub(e) {
    e.preventDefault();

    const { name, email } = formInfo;

    if (name === "") {
      alert("fill your name");
    } else if (email === "") {
      alert("fill out your email");
    } else {
      alert("done");
      setFormInfo({ name: "", email: "" });
    }
  }

  const { name, email } = formInfo;

  return (
    <form action="" onSubmit={onsub}>
      <div className="input">
        <label htmlFor="">Name</label>
        <input type="text" name="" id="name" onChange={onch} value={name} />
      </div>
      <div className="input">
        <label htmlFor="">E-mail</label>
        <input type="text" name="" id="email" onChange={onch} value={email} />
      </div>

      <div className="input">
        <button type="submit">Submit</button>
      </div>
    </form>
  );
}

You see if you didn't fill out one of the inputs it will trigger an alert. But I want to replace the alert with focus instead. So when I forgot to fill out a certain input it will focus on that empty input basically telling me to fill it out.

THANK YOU IN ADVANCE

4

There are 4 best solutions below

0
On

You can create something like this which use createRef() api of react.

class MyComponent extends React.Component {
constructor(props) {
super(props);

this.inputRef = React.createRef();
}

render() {
return <input type="text" ref={this.inputRef} />;
}

componentDidMount() {
this.inputRef.current.focus();
}
}

This sample is taken from react.org

4
On

Updated

After some deliberations, I wanted to showcase how to use querySelector in react correctly, and in the process simplify the example:

import React, { useCallback, useRef } from "react";

export default function App() {
  const formRef = useRef(null);

  const handleSubmit = useCallback((e) => {
    e.preventDefault();

    const formData = new FormData(e.target);

    for (let [name, value] of formData.entries()) {
      if (!value) {
        formRef.current.querySelector(`input[name=${name}]`).focus()
        break
      }
    }
    // do something with the formData
  }, []);

  return (
    <form ref={formRef} action="" onSubmit={handleSubmit}>
      <div className="input">
        <label htmlFor="">Name</label>
        <input type="text" name="name" id="name" />
      </div>
      <div className="input">
        <label htmlFor="">E-mail</label>
        <input type="text" name="email" id="email" />
      </div>

      <div className="input">
        <button type="submit">Submit</button>
      </div>
    </form>
  );
}


you can access the target (the form) in the event, and then query inside it to reach the element you're looking for, and focus them. No need for react ref in this case. Do note, it is usually not recommended to query the DOM directly. The docs do specify managing focus as an intended use for refs, as seen here

import React, { useState } from "react";
import "./styles.css";

export default function App() {

  const [formInfo, setFormInfo] = useState({name: '', email: ''})


  function onch(e){
    const {value, id} = e.target

    id === 'name' ? setFormInfo({...formInfo, name: value}) : setFormInfo({...setFormInfo, email: value})

  }

  function onsub(e){
    e.preventDefault()

    const {name, email} = formInfo
    
    if(name === ''){
      e.target.querySelector('#name').focus()
    }
    else if(email === ''){
      e.target.querySelector('#email').focus()
    }else{
      alert('done')
      setFormInfo({name: '', email: ''})
    }
    
  }

  const {name, email} = formInfo

  return (
  <form action="" onSubmit={onsub}>

    <div className="input">
      <label htmlFor="">Name</label>
      <input type="text" name="" id="name" onChange={onch} value={name}/>
    </div>
    <div className="input">
      <label htmlFor="">E-mail</label>
      <input type="text" name="" id="email" onChange={onch} value={email}/>
    </div>
   
    <div className="input">
      <button type="submit">Submit</button>
    </div>

  </form>
  );
}


0
On

You should use ref to get access to an element and then trigger focus() for it. There is useRef hook to do this. Your code will be:

import React, { useState, useRef } from "react";

export default function App() {
  const [formInfo, setFormInfo] = useState({ name: "", email: "" });
  const nameRef = useRef();
  const emailRef = useRef();

  function onch(e) {
    const { value, id } = e.target;

    id === "name"
      ? setFormInfo({ ...formInfo, name: value })
      : setFormInfo({ ...setFormInfo, email: value });
  }

  function onsub(e) {
    e.preventDefault();

    const { name, email } = formInfo;

    if (name === "") {
      nameRef.current.focus();
    } else if (email === "") {
      emailRef.current.focus();
    } else {
      alert("done");
      setFormInfo({ name: "", email: "" });
    }
  }

  const { name, email } = formInfo;

  return (
    <form action="" onSubmit={onsub}>
      <div className="input">
        <label htmlFor="">Name</label>
        <input
          type="text"
          name=""
          id="name"
          onChange={onch}
          value={name}
          ref={nameRef}
        />
      </div>
      <div className="input">
        <label htmlFor="">E-mail</label>
        <input
          type="text"
          name=""
          id="email"
          onChange={onch}
          value={email}
          ref={emailRef}
        />
      </div>

      <div className="input">
        <button type="submit">Submit</button>
      </div>
    </form>
  );
}

To learn more about ref read documentation.

0
On

You can achieve this using useRef hook, the code with give the focus to the first empty element and make its borders red

 import React, { useState, useRef } from "react";

 export default function App() {
 const [formInfo, setFormInfo] = useState({ name: "", email: "" });

function onch(e) {
const { value, id } = e.target;

id === "name"
  ? setFormInfo({ ...formInfo, name: value })
  : setFormInfo({ ...setFormInfo, email: value });
}

const nameRef = useRef();
const emailRef = useRef();

function onsub(e) {
e.preventDefault();

const { name, email } = formInfo;

if (name === "") {
  nameRef.current.focus();
  nameRef.current.style.border = "1px solid red";
} else if (email === "") {
  nameRef.current.focus();
  nameRef.current.style.border = "1px solid red";
} else {
  alert("done");
  setFormInfo({ name: "", email: "" });
}
}

const { name, email } = formInfo;

return (
<form action="" onSubmit={onsub}>
  <div className="input">
    <label htmlFor="">Name</label>
    <input
      ref={nameRef}
      type="text"
      name=""
      id="name"
      onChange={onch}
      value={name}
    />
  </div>
  <div className="input">
    <label htmlFor="">E-mail</label>
    <input
      ref={emailRef}
      type="text"
      name=""
      id="email"
      onChange={onch}
      value={email}
    />
  </div>

  <div className="input">
    <button type="submit">Submit</button>
  </div>
</form>
);
}