On This Page
- # Key Steps to Build React Input Component:
- # React Input UI without Error
- # React Input UI with Error
- # Reusable Input Component Architecture
- # JSX for React Input Component with label and error
- # CSS for Reusable Input Component
- # Best Practices for Creating Reusable Input Components in React
- # Codepen Demo | Reusable Input Component
Every website deals with forms, and input is one of the most essential and frequently used form elements. This guide will cover:
- How to create a reusable input component in React using TypeScript
- Handling error messages effectively
- Making the component modular using a
useInput
custom hook - Best UI/UX practices for creating input components
Key Steps to Build React Input Component:
- Component Architecture & UI
- Build the structure of the input component
- Design the UI with and without error states
- Functionality Implementation
- Add functionality to control input component uing
useState
hook - Error handling and user-friendly interactions
- Add functionality to control input component uing
The Codepen demo is also available at the end of the article.
Here is the design of our input component with and without error.
React Input UI without Error

React Input UI with Error

Reusable Input Component Architecture
Let's talk about component architecture.
The input component has multiple props. It depends on your choice that what you want to keep and remove as required. The following are the possible props:
-
type
: Specifies the type of input (e.g.,'text'
,'number'
,'email'
,'password
'). -
label
: The text for the input label. -
value
: The current value of the input. -
error
: An error message to display which is optional and shown on the basis of condition. -
name
: Represents the name attribute of the input element to identify and group the data submitted from different input fields -
placeholder
: The placeholder text to display when the input is empty. -
onChange
: The function to handle changes in the input value. It takes an event of typeChangeEvent<HTMLInputElement>
as a parameter. -
disabled
: which is optional (indicated by the?
symbol). It specifies whether the input should be disabled or not
JSX for React Input Component with label and error
import { ChangeEvent, FC } from 'react'interface InputProps {type: 'text' | 'number' | 'email' | 'password'label: stringvalue: string | numbername: stringplaceholder: stringerror: booleandisabled?: booleanonChange: (e: ChangeEvent<HTMLInputElement>) => void}const Input: FC<InputProps> = ({type,label,value,name,placeholder,error,disabled,onChange,}) => {return (<div className="input-wrapper"><label htmlFor={label}>{label}</label><inputtype={type}id={label}value={value}name={name}placeholder={placeholder}onChange={onChange}disabled={disabled}/>{error && <p className="error">Input filed can't be empty!</p>}</div>)}export default Input
CSS for Reusable Input Component
.input-wrapper {margin-top: 20px;}/* Input style *//* Label */label {font-weight: 600;font-size: 18px;color: #344054;display: block;margin-bottom: 8px;}/* Input field */input {font-size: 16px;font-weight: 400;width: 250px;color: #344054;background: #ffffff;border: 1px solid #d0d5dd;box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);border-radius: 8px;padding: 10px 14px;}input::placeholder {font-size: 16px;font-weight: 400;color: #667085;}/* Input field focus */input:focus {}.error {color: #db4437;font-size: 14px;font-weight: 400;margin-left: 12px;margin-top: 4px;}
This is how our input component UI will look like if we will render it in App
or parent component

We are done with component structure, architecture, and UI, now let's make it functional and see how we can use it in real world applications.
How to use Input Component with form
Let's say we are working on a login form in React App and want to use this input component there. In the below-given component, we import the Input component first and make two states, one for input value and the other for error.
While submitting the form, we check for an error and then show the error.
import React, { ChangeEvent, FormEvent, useState } from 'react'import './App.css'import Input from './components/Input'const App: React.FC = () => {const [name, setName] = useState('')const [error, setError] = useState(false)const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {setName(e.target.value)}const handleSubmit = (e: FormEvent<HTMLFormElement>) => {e.preventDefault()if (!name.trim()) {setError(true)} else {setError(false)}}return (<div className="page-center"><form onSubmit={handleSubmit}><h3 className="form-title">Login Form</h3><Inputtype="text"label="Name"value={name}name="name"error={error}onChange={handleNameChange}placeholder="Please enter your name"/><button type="submit">Submit</button></form></div>)}export default App
Note
This is the boilerplate code you can tweak it as per your need.
Best Practices for Creating Reusable Input Components in React
You can get most out of reusable input components with some best practices. You must consider these while working on forms or input in React APP.
So, let’s see what are these practices:
1. Call handleSubmit
function in form
Always wrap input
inside form
and call submit function in form tag
and make the submit button type="submit"
, it will invoke submit function both ways, by pressing submit button and enter key on the keyboard.
2. When to disable Input in React
Input tag also supports disabled
prop, when to use it? It depends on the app use case, some developers make the input and submit form button both disable while submitting data to database to prevent retyping in input until you get the response back from database.
You can also learn more about how to use the loading spinner button in React, which I have discussed in this article.
3. Using htmlFor attribute for activating input by clicking a label
We also need to improve the UX of input component. There are two ways to activate input.
- Click the input box
- Click the label
We also have to implement the second point to improve the UX of the component.
The label
element is associated with the input using the htmlFor
attribute, which matches the id
of the input element. This helps in accessibility by associating the label with the correct input.
4. useInput custom hook
Using the custom useInput hook we can further improve input component by making it modular and scalable.
import { ChangeEvent, useState } from 'react'const useInput = (initialValue: string) => {const [value, setValue] = useState(initialValue)const [error, setError] = useState(false)const handleChange = (e: ChangeEvent<HTMLInputElement>) => {setValue(e.target.value)}return {value,error,onChange: handleChange,setError,}}export default useInput
How to use useInput
hook in form;
import React, { FormEvent } from 'react'import './App.css'import Input from './components/Input'import useInput from './hooks/useInput'const App: React.FC = () => {const { value, error, onChange, setError } = useInput('')const handleSubmit = (e: FormEvent<HTMLFormElement>) => {e.preventDefault()if (!value.trim()) {setError(true)} else {setError(false)}}return (<div className="page-center"><form onSubmit={handleSubmit}><Inputtype="text"label="Name"name="name"value={value}error={error}onChange={onChange}placeholder="Please enter your name"/><button type="submit">Submit</button></form></div>)}export default App
What if you want to use two inputs in the form and that is email and password? If this is the case I will refactor the code this way;
import React, { FormEvent } from 'react'import './App.css'import Input from './components/Input'import useInput from './hooks/useInput'const App: React.FC = () => {const emailInput = useInput('')const passwordInput = useInput('')const handleSubmit = (e: FormEvent) => {e.preventDefault()validateInput(emailInput)validateInput(passwordInput)console.log('email ==>', emailInput.value, 'password ==>', passwordInput.value)}const validateInput = (input: { value: string, setError: (value: boolean) => void }) => {if (!input.value.trim()) {input.setError(true)} else {input.setError(false)}}return (<div className="page-center"><form onSubmit={handleSubmit}><h3 className="form-title">Login Form</h3><Inputtype="email"label="Email"name="email"placeholder="Please enter your email"{...emailInput}/><Inputtype="password"label="Password"name="password"placeholder="Please enter your password"{...passwordInput}/><button className="submit-btn">Submit</button></form></div>)}export default App
While submitting the form we are checking if the input values are safely added to our state and verify the functionality of the useInput hook with console.log()

Further Read
If you have a form with more than one input, there is one more pattern useForm
custom hook I teach in React forms best practices article.
If you are designing an input component with Tailwind CSS, copy the code from this doc: Input Component with Tailwind CSS.
Codepen Demo | Reusable Input Component
I hope you learned something new in this article that helps you in your React journey. Want to learn more about React? Do subscribe to the newsletter for more insightful content.