📖 Deeper dive reading:
Tailwind is a CSS framework that takes a different approach from traditional frameworks. Instead of simply importing a bunch of predefined CSS class name selectors for things such as buttons or navbars, Tailwind provides low-level utility classes that you apply directly in your HTML.
- Created by: Adam Wathan, Steve Schoger, Jonathan Reinink, and David Hemphill
- Initial release: November 2017
- Motivation: The team behind Tailwind wanted a way to build UIs faster and more flexibly without constantly switching between HTML and CSS files or overriding styles from traditional frameworks like Bootstrap.
- Success: It has grown to become the most popular CSS frameworks due to its developer-first philosophy and modern tooling ecosystem.
When you use Tailwind you simply add standard Tailwind class names to your HTML elements. You then run the HTML through a tool chain process, for example with Vite, and it dynamically builds your CSS files from the classes that you explicitly reference.
This has several advantages. It reduces CSS bloat, puts your styling directly in the HTML where it is used, and increases performance because you only include styling that you actually use. It also is closer to CSS and so if you are familiar with CSS you can quickly style your HTML using a simplified style syntax.
Tailwind works really well with web component frameworks because it encourages you to build reusable components in a framework like React so that you avoid creating similar components with slightly different Tailwind class references.
Here is an example of a button that is styled with Tailwind.
<button className="bg-blue-400 text-white px-4 py-2 rounded shadow hover:bg-blue-700 transition-colors m-4">Get Started</button>You can get a deeper understanding of Tailwind by comparing it to the popular Bootstrap CSS framework. The following example shows that same HTML that is styled first with Bootstrap and then Tailwind.
With Bootstrap you use Bootstrap's card, card-body, card-tile, and card-text component classes. The HTML then references a large static stylesheet in order to apply the CSS rule sets for the classes.
<div class="card" style="width: 18rem;">
<img class="card-img-top" src="https://picsum.photos/400/200" />
<div class="card-body">
<h5 class="card-title">Card Title</h5>
<p class="card-text">Some quick example text.</p>
</div>
</div>With Tailwind there are no component level definitions. You simply work with class names that are similar to primitive CSS directives. You apply the class names directly in the HTML and not through CSS files.
<div class="max-w-sm rounded overflow-hidden">
<div className="max-w-sm rounded bg-white overflow-hidden shadow-lg m-4 p-2">
<img className="w-full" src="https://picsum.photos/400/200" />
<div className="px-2 py-4">
<div className="font-bold text-xl mb-2">Card Title</div>
<p className="text-gray-700 text-base">Some quick example text.</p>
</div>
</div>The visual result is similar in either case.
However, because Bootstrap uses predefined component level classes, you will need to download the entire Bootstrap CSS framework file in order to render the card. With Tailwind, a custom CSS file is created dynamically for you that only contains the styling that you used.
You may be concerned about all of those "css declarations" being put directly on the HTML elements, but in reality you would use a web framework to modularize the entire card into a component and so there is no real duplication of the "css declarations". You are just specifying the component's CSS right where it is used rather in a different file that is referenced by a class name selector.
| Feature | Tailwind CSS | Bootstrap |
|---|---|---|
| Philosophy | Utility-first (build from primitives) | Component-based (prebuilt UI components) |
| Customization | Highly customizable via config (tailwind.config.js) |
Customizable but more rigid without overrides |
| Design freedom | Full control over spacing, color, layout | Limited to pre-defined component styling |
| File size | Smaller | Larger due to bundled components and styles |
| Learning curve | Steep at first as you learn native CSS | Easy to get started |
| JS dependency | No JS (except if using plugins) | Depends on jQuery (Bootstrap ≤ 4) or native JS (Bootstrap 5) |
Tailwind requires a tool chain processor to convert the class names into a CSS stylesheet. You will include the necessary processor when you move your startup application to React. However, for now you can play with with Tailwind right now by creating a Hello World React application and then configuring Vite to support tailwind.
The steps involved include creating the demo application, installing tailwind, configuring Vite to execute tailwind as part of the tool chain, adding a reference to the resulting CSS, and adding Tailwind class names to your HTML elements.
-
Start with the Hello World React application. This will result in an application that looks like this:
When you are done configuring Tailwind the application should look very similar.
-
Install Tailwind CSS
npm install tailwindcss @tailwindcss/vite
-
Configure the Vite plugin to use Tailwind to compile the CSS by modifying/creating
vite.config.jsimport { defineConfig } from 'vite'; import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [tailwindcss()], });
-
Create a
index.cssfile and import tailwindcss. This will bring in the dynamically generated Tailwind CSS file.@import 'tailwindcss';
-
Modify
index.htmlhead element to reference the placeholder CSS file.<link href="/src/style.css" rel="stylesheet" />
-
Modify the
index.jsxfile to use Tailwind classes.import React from 'react'; import ReactDOM from 'react-dom/client'; function App() { const [bgColor, setBgColor] = React.useState('bg-white'); const handleClick = () => { setBgColor(bgColor === 'bg-white' ? 'bg-yellow-200' : 'bg-white'); }; return ( <div onClick={handleClick} className={`h-screen font-bold text-8xl flex items-center justify-center ${bgColor}`}> <div> Hello React </div> </div> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);


