Skip
Arish's avatar

25. Tailwind CSS with React


Tailwind CSS with React

Tailwind CSS is a utility-first framework that integrates beautifully with React.

Installation

bash
1npm install -D tailwindcss postcss autoprefixer
2npx tailwindcss init -p
javascript
1// tailwind.config.js
2export default {
3  content: [
4    "./index.html",
5    "./src/**/*.{js,ts,jsx,tsx}",
6  ],
7  theme: {
8    extend: {},
9  },
10  plugins: [],
11}
css
1/* index.css */
2@tailwind base;
3@tailwind components;
4@tailwind utilities;

Basic Usage

jsx
1function Card({ title, children }) {
2  return (
3    <div className="bg-white rounded-lg shadow-md p-6 max-w-md mx-auto">
4      <h2 className="text-2xl font-bold text-gray-800 mb-4">{title}</h2>
5      <p className="text-gray-600 leading-relaxed">{children}</p>
6    </div>
7  )
8}

Responsive Design

jsx
1function ResponsiveGrid({ items }) {
2  return (
3    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
4      {items.map(item => (
5        <div 
6          key={item.id} 
7          className="bg-white p-4 rounded shadow
8                     sm:p-6 
9                     md:p-8"
10        >
11          <h3 className="text-lg md:text-xl lg:text-2xl font-bold">
12            {item.title}
13          </h3>
14        </div>
15      ))}
16    </div>
17  )
18}

Interactive States

jsx
1function Button({ children }) {
2  return (
3    <button className="
4      bg-blue-500 text-white px-4 py-2 rounded
5      hover:bg-blue-600
6      focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
7      active:bg-blue-700
8      disabled:opacity-50 disabled:cursor-not-allowed
9      transition-colors duration-200
10    ">
11      {children}
12    </button>
13  )
14}

Conditional Classes with clsx

bash
1npm install clsx
jsx
1import clsx from 'clsx'
2
3function Button({ variant, size, disabled, children }) {
4  return (
5    <button
6      className={clsx(
7        // Base styles
8        'font-medium rounded transition-colors',
9        
10        // Variants
11        {
12          'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
13          'bg-gray-200 text-gray-800 hover:bg-gray-300': variant === 'secondary',
14          'bg-red-500 text-white hover:bg-red-600': variant === 'danger',
15          'bg-transparent border border-gray-300 hover:bg-gray-50': variant === 'outline',
16        },
17        
18        // Sizes
19        {
20          'text-sm px-3 py-1.5': size === 'small',
21          'px-4 py-2': size === 'medium',
22          'text-lg px-6 py-3': size === 'large',
23        },
24        
25        // States
26        {
27          'opacity-50 cursor-not-allowed': disabled,
28        }
29      )}
30      disabled={disabled}
31    >
32      {children}
33    </button>
34  )
35}

Dark Mode

javascript
1// tailwind.config.js
2export default {
3  darkMode: 'class',
4  // ...
5}
jsx
1function ThemeToggle() {
2  const [dark, setDark] = useState(false)
3  
4  useEffect(() => {
5    document.documentElement.classList.toggle('dark', dark)
6  }, [dark])
7  
8  return (
9    <button onClick={() => setDark(!dark)}>
10      {dark ? '☀️' : '🌙'}
11    </button>
12  )
13}
14
15function Card() {
16  return (
17    <div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-white p-6 rounded-lg shadow">
18      <h2 className="text-xl font-bold">Title</h2>
19      <p className="text-gray-600 dark:text-gray-300">Content</p>
20    </div>
21  )
22}

Component Patterns

Reusable Input

jsx
1function Input({ label, error, ...props }) {
2  return (
3    <div className="mb-4">
4      {label && (
5        <label className="block text-sm font-medium text-gray-700 mb-1">
6          {label}
7        </label>
8      )}
9      <input
10        className={clsx(
11          'w-full px-3 py-2 border rounded-md shadow-sm',
12          'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500',
13          error
14            ? 'border-red-500 focus:ring-red-500 focus:border-red-500'
15            : 'border-gray-300'
16        )}
17        {...props}
18      />
19      {error && (
20        <p className="mt-1 text-sm text-red-600">{error}</p>
21      )}
22    </div>
23  )
24}
jsx
1function Modal({ isOpen, onClose, title, children }) {
2  if (!isOpen) return null
3  
4  return (
5    <div className="fixed inset-0 z-50 overflow-y-auto">
6      {/* Backdrop */}
7      <div 
8        className="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
9        onClick={onClose}
10      />
11      
12      {/* Modal */}
13      <div className="flex min-h-full items-center justify-center p-4">
14        <div className="relative bg-white rounded-lg shadow-xl max-w-lg w-full p-6">
15          <div className="flex items-center justify-between mb-4">
16            <h2 className="text-xl font-bold">{title}</h2>
17            <button 
18              onClick={onClose}
19              className="text-gray-400 hover:text-gray-600"
20            >
2122            </button>
23          </div>
24          <div>{children}</div>
25        </div>
26      </div>
27    </div>
28  )
29}

Badge

jsx
1function Badge({ variant = 'default', children }) {
2  const variants = {
3    default: 'bg-gray-100 text-gray-800',
4    success: 'bg-green-100 text-green-800',
5    warning: 'bg-yellow-100 text-yellow-800',
6    danger: 'bg-red-100 text-red-800',
7    info: 'bg-blue-100 text-blue-800',
8  }
9  
10  return (
11    <span className={clsx(
12      'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium',
13      variants[variant]
14    )}>
15      {children}
16    </span>
17  )
18}

Custom Theme

javascript
1// tailwind.config.js
2export default {
3  theme: {
4    extend: {
5      colors: {
6        primary: {
7          50: '#eff6ff',
8          500: '#3b82f6',
9          600: '#2563eb',
10          700: '#1d4ed8',
11        },
12        brand: '#ff6b6b',
13      },
14      fontFamily: {
15        sans: ['Inter', 'sans-serif'],
16      },
17      spacing: {
18        '128': '32rem',
19      },
20    },
21  },
22}
jsx
1<button className="bg-primary-500 hover:bg-primary-600">
2  Primary
3</button>

@apply Directive

For reusable component styles:

css
1/* styles.css */
2@layer components {
3  .btn {
4    @apply px-4 py-2 font-medium rounded transition-colors;
5  }
6  
7  .btn-primary {
8    @apply bg-blue-500 text-white hover:bg-blue-600;
9  }
10  
11  .card {
12    @apply bg-white rounded-lg shadow-md p-6;
13  }
14}
jsx
1<button className="btn btn-primary">Click me</button>
2<div className="card">Card content</div>

Tailwind CSS makes styling React components fast and consistent!