Reputation: 755
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
Upvotes: 1
Views: 5812
Reputation: 325
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>
);
}
Upvotes: -1
Reputation: 477
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>
);
}
Upvotes: 2
Reputation: 1222
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.
Upvotes: 1
Reputation: 706
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
Upvotes: 0