Hello folks,
Few days ago, I was searching for some good CSS solutions for my side project and during that I came across Tailwind. Tailwind is surely becoming popular amongst many developers these days, and after using it, I understood the reason. It is a utility-first CSS framework, and when they say utility-first, it means it provides some low-level CSS classes which can be used to write CSS without writing CSS.
After using Tailwind, initially it started feeling a little weird looking at the long list of class names I needed to add to components. But later, after following some practices, it started getting better. Though it's been only a few days I am using Tailwind, but I thought of writing this tutorial as a starter for anyone who wants to use Tailwind with React.
In this tutorial, we will be creating a simple login page in React using Tailwind and exploring some methods to use tailwind. While reading ahead, please note, these are some practices which I follow and if you know some better ways, I would love to know them! So do share them in comments.
To get started, I created a project using create-react-app
and added tailwind to it as a dependency by following simple steps mentioned in Tailwind’s official documentation. You can follow the same steps as I have not included them in this article considering the scope.
Moving ahead, I created a component called login.js
for our login page. Initially it looked something like this -
import React from 'react';
const Login = () => {
const handleFormSubmit = (e) => {
e.preventDefault();
let email = e.target.elements.email?.value;
let password = e.target.elements.password?.value;
console.log(email, password);
};
return (
<div>
<div>
<h1>Log in to your account 🔐</h1>
<form onSubmit={handleFormSubmit}>
<div>
<label htmlFor='email'>Email</label>
<input
type='email'
id='email'
placeholder='Your Email'
/>
</div>
<div>
<label htmlFor='password'>Password</label>
<input
type='password'
id='password'
placeholder='Your Password'
/>
</div>
<div>
<button>Login</button>
</div>
</form>
</div>
</div>
);
};
export default Login;
The above code looks something like this -
Bare minimum! Now the first thing we need to do is to create a card like structure around this form and center it to the page. In Tailwind, we don't have bootstrap like ready-made components, so we will be using all the utility classes to structure our own. I started off with the most outer div element and give it basic three classes which is - h-screen flex bg-gray-100
. This list is adding three CSS properties to our outer div, which are height, flex property and a background color. You must be thinking, whoa.. 3 classes for 3 CSS properties??, that’s the utility-first approach used in Tailwind. But bear with this, it will soon start making sense!!
Similarly, we will add styles to the form card by adding these classes w-full max-w-md m-auto bg-white rounded-lg border border-gray-200 shadow-default py-10 px-16
. Here because we have added max width to the card as md (28 rem), it will get restricted to 28px width and m-auto will set margin auto making it center into the page. All other classes are just to add more aesthetics to the card. The thumb rule for getting started with Tailwind would be, think of which CSS properties you would add to your element and start searching for those classes in Tailwind documentation. After adding some basic tailwind classes, our login page will look something like this -
Here is the code for above page -
import React from 'react';
const Login = () => {
const handleFormSubmit = (e) => {
e.preventDefault();
let email = e.target.elements.email?.value;
let password = e.target.elements.password?.value;
console.log(email, password);
};
return (
<div className='h-screen flex bg-gray-bg1'>
<div className='w-full max-w-md m-auto bg-white rounded-lg border border-primaryBorder shadow-default py-10 px-16'>
<h1 className='text-2xl font-medium text-primary mt-4 mb-12 text-center'>
Log in to your account 🔐
</h1>
<form onSubmit={handleFormSubmit}>
<div>
<label htmlFor='email'>Email</label>
<input
type='email'
className={`w-full p-2 text-primary border rounded-md outline-none text-sm transition duration-150 ease-in-out mb-4`}
id='email'
placeholder='Your Email'
/>
</div>
<div>
<label htmlFor='password'>Password</label>
<input
type='password'
className={`w-full p-2 text-primary border rounded-md outline-none text-sm transition duration-150 ease-in-out mb-4`}
id='password'
placeholder='Your Password'
/>
</div>
<div className='flex justify-center items-center mt-6'>
<button
className={`bg-green py-2 px-4 text-sm text-white rounded border border-green focus:outline-none focus:border-green-dark`}
>
Login
</button>
</div>
</form>
</div>
</div>
);
};
export default Login;
Instead of providing CSS classes for full components, Tailwind gives you some low level utility classes, using which you can design your own custom components. I have mostly used Bootstrap for most of the projects, but I was fed up with overwriting its classes most of the time. Also, it used to give the same UI look and feel for each and every project and I was looking for some change.
Two things to notice here -
Some classnames seems different than the documentation for e.g. bg-green
, border-green-dark
and text-primary
Many things are repetitive and the classNames list is too long which is losing the readability of components.
As you see, all the different classNames are about the customisations which we can make into the Tailwind’s config. In your project, while you add Tailwind, you will create one file called tailwind.config.js which will be responsible for all the customisations you will want to make in your app. It may include adding new color schemes, adding new font-sizes etc. For e.g. config file for this project will look something like this
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
darkMode: false, // or 'media' or 'class'
theme: {
colors: {
transparent: 'transparent',
current: 'currentColor',
white: {
DEFAULT: '#ffffff',
},
green: {
light: '#6fcf97',
DEFAULT: '#27AE60',
dark: '#219653',
darker: '#1e874b',
},
red: {
light: '#FFEAEA',
DEFAULT: '#EB5757',
dark: '#C20D0D',
},
orange: {
light: '#FFEBDA',
DEFAULT: '#F66A0A',
dark: '#A04100',
},
primary: {
DEFAULT: '#24292E',
},
warning: {
DEFAULT: '#D1711C',
}
},
extend: {
boxShadow: {
default: '0px 10px 20px rgba(150, 150, 187, 0.1)',
},
fontSize: {
'2rem': '2rem',
},
},
},
variants: {
extend: {},
},
plugins: [],
};
Moving to the second issue, few components are getting repetitive, like input and buttons. An obvious solution to that would be creating components for such elements. But even creating components won’t solve the issue of long className lists. For that, let's create variables and assign classLists to them. In that case, your css will be completely different than JS, your code will be more readable and you can reuse those variables. Even it will add scalability to certain extent.
Let’s see how this looks in a code -
import React from 'react';
import { PrimaryButton } from '../components/FormElements/Button';
import Input from '../components/FormElements/Input';
const Login = () => {
const handleFormSubmit = (e) => {
e.preventDefault();
let email = e.target.elements.email?.value;
let password = e.target.elements.password?.value;
console.log(email, password);
};
const classes = {
pageBody: 'h-screen flex bg-gray-bg1',
formContainer:
'w-full max-w-md m-auto bg-white rounded-lg border border-primaryBorder shadow-default py-10 px-16',
formHeading: 'text-2xl font-medium text-primary mt-4 mb-12 text-center',
btnContainer: 'flex justify-center items-center mt-6',
};
return (
<div className={classes.pageBody}>
<div className={classes.formContainer}>
<h1 className={classes.formHeading}>
Log in to your account 🔐
</h1>
<form onSubmit={handleFormSubmit}>
<Input
id='email'
label='Email'
type='email'
placeholder='Your email'
/>
<Input
id='password'
label='Password'
type='password'
placeholder='Your Password'
/>
<div className={classes.btnContainer}>
<PrimaryButton type='submit'>
Continue with Email
</PrimaryButton>
</div>
</form>
</div>
</div>
);
};
export default Login;
In the code above, I have created an object called classes
and added a long classNames list to it as a key value pair. This separated CSS classes from JS and made the code easily readable. Apart from that, I also created some basic components for Inputs and Buttons
In the code above, I have created an object called classes
and added a long classNames list to it as a key value pair. This separated CSS classes from JS and made the code easily readable. Apart from that, I also created some basic components for Inputs and Buttons.
So, That’s it!! We have already created a simple login form. I know this is still a dumb component and we have not included error handling, responsiveness and API calls. But I am keeping this out of scope for this article and will cover that in my next one.
Till then, please share your thoughts and approaches of handling integrating Tailwind CSS into your React projects!
You can also connect with me on Twitter or buy me a coffee if you like my articles.
Keep learning :)