Form inputs with React and Tailwind
Tags: react, tailwindcss, javascript, tutorial
Published: 2021-05-11 10:46:28

Hello There, 

TailwindCSS is a utility-first library which encourages to build everything using it's utility classes. With growing projects, we see the set of elements repeating themselves. With a utility-first approach, we not only repeat the list of classes but also the html structure of those elements. Best and well known way of handling this is creating components for mostly used elements. 

In this article, I will be covering one mostly used component in any project - **Form Input**. Let’s dive in and understand how we can create it.

 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2txob2d4fw2mos7anso.png)  

We will be creating an input element similar to the input shown in the image above. Let’s divide the whole process into 3 different parts - 
1. Styling the element.
2. Handling error. 
3. Improving its usability.

### 1. Styling the element

If you notice, the input element has a label and border around both label and input. So let's take a wrapper div and put our label plus input element inside it. Hence the HTML look something like this - 

```javascript 
const Input = (props) => {
	const { id, placeholder = '', label = '', type = 'text', ...rest } = props;
	return (
		<div>
			<label htmlFor={id}>{label}</label>
			<input type={type} id={id} placeholder={placeholder} {...rest} />
		</div>
	);
};

export default Input;
```
This is the simplest react component which will take `id`, `label`, `type` and `placeholder` as a prop and we have also added `...rest` to maintain its flexibility. 

Now, to add styling, the idea is, add a border to the outer div and place the label inside. Also, hide the border for the input element. 

After adding Tailwind's utility classes this input will look like this - 

```javascript
const Input = (props) => {
	const { id, placeholder = '', label = '', type = 'text', ...rest } = props;
	return (
		<div
			className={`border transition duration-150 ease-in-out focus-within:border-primary border-gray-gray4`}
		>
			<label
				htmlFor={id}
				className={`text-xs text-primary font-light placeholder-gray-gray4 px-2 pt-1.5`}
			>
				{label}
			</label>
			<input
				type={type}
				className={`w-full px-2 pb-1.5 text-primary outline-none text-base font-light rounded-md`}
				id={id}
				placeholder={placeholder}
				{...rest}
			/>
		</div>
	);
};

export default Input;
```

Notice how we have used `focus-within` property to change the border color after focusing input.

Till this point, we have already created a good looking input element. But, this element still have two issues - 
1. It will not show error
2. If a user clicks on the box, outside the `<input/>` tag, the input will not be focused. 

Let's solve these issues now. 

### 2. Handling input error

To show input error efficiently, we will need to add two things, we will need to make the border red when error occurs and we will need to show error text below the input component.

Let's see the code first - 

```javascript
const Input = (props) => {
	const {
		id,
		wrapperClassName = '',
		placeholder = '',
		label = '',
		type = 'text',
		error = '',
		required = false,
		...rest
	} = props;

	return (
		<div className={wrapperClassName}>
			<div
				className={`border transition duration-150 ease-in-out ${
					error
						? 'focus-within:border-red border-red'
						: 'focus-within:border-primary border-gray-gray4'
				}`}
			>
				<label
					htmlFor={id}
					className='text-xs text-primary font-light placeholder-gray-gray4 px-2 pt-1.5'
				>
					{label} {required && <span className='text-red'>*</span>}
				</label>
				<input
					type={type}
					className='w-full px-2 pb-1.5 text-primary outline-none text-base font-light rounded-md'
					id={id}
					placeholder={placeholder}
					{...rest}
				/>
			</div>
			{error && <p className='text-xs pl-2	text-red mb-4'>{error}</p>}
		</div>
	);
};

export default Input;
``` 

Here, to add the error, we added a `<p>` tag in the bottom. As React needs only a single element wrapper, we added one more `div` outside. This div will be helpful to add margins or other styles to complete the input component.

We have also changed the border color conditionally for the outer component and added an asterisk, if the input is mandatory. 

With this error handling, we have almost finished creating out component. One last thing pending here is, focusing our input when we click the outer div.

### 3. Improving usability

To focus our input on after clicking the outside div, we have `useRef` to our rescue😅. We added a ref to the input element inside our component. When we will click the outside div, we will add focus to the input using this ref. 

Notice the `onClick` event we added to the outside div of input. This will solve all our requirements and a complete input component becomes ready.

Final version of our component will look something like this -

```javascript
import { useRef } from 'react';

const Input = (props) => {
	const {
		id,
		wrapperClassName = '',
		placeholder = '',
		label = '',
		type = 'text',
		error = false,
		errorText = '',
		required = false,
		...rest
	} = props;

	const inputRef = useRef();

	return (
		<div className={wrapperClassName}>
			<div
				className={`border transition duration-150 ease-in-out ${
					error
						? 'focus-within:border-red border-red'
						: 'focus-within:border-primary border-gray-gray4'
				}`}
				onClick={() => inputRef.current.focus()}
			>
				<label
					htmlFor={id}
					className='text-xs text-primary font-light placeholder-gray-gray4 px-2 pt-1.5'
				>
					{label} {required && <span className='text-red'>*</span>}
				</label>
				<input
					ref={inputRef}
					type={type}
					className='w-full px-2 pb-1.5 text-primary outline-none text-base font-light rounded-md'
					id={id}
					placeholder={placeholder}
					{...rest}
				/>
			</div>
			{errorText && (
				<p className='text-xs pl-2	text-red mb-4'>{errorText}</p>
			)}
		</div>
	);
};

export default Input;

```

And that's it! 

You can create many such components using Tailwind and React. I have used this code for my [side project](http://peerlist.io/) and I am creating more such components in my [github repository](https://github.com/ms-yogi/React-Tailwind-Component). 

Thank you so much for reading this article and always happy to receive your feedback. You can also connect with me on [Twitter](https://twitter.com/hey_yogini) or [buy me a coffee](https://www.buymeacoffee.com/heyyogini) if you like my articles. 

Thanks a lot! Keep learning 🙌