Skip to main content
Tech Stack progress
intermediatePage 6 of 27

Styling

How you write CSS shapes the entire development experience. Tailwind dominates; shadcn/ui is the component layer of choice.

Styling

In one line: Tailwind CSS + shadcn/ui is the dominant 2026 styling stack. Old-school CSS Modules still work fine; CSS-in-JS is fading.

Going deeper: Advanced CSS & Styling covers the cascade and specificity, stacking contexts, modern layout, and design tokens.

In plain English

"Styling" is the layer that makes things look right — colors, spacing, fonts, hover states. Modern frontend has converged on utility-first CSS (Tailwind) — instead of writing custom class names like .primary-button, you compose pre-made utility classes (px-4 py-2 bg-blue-500 rounded). Combined with a component collection like shadcn/ui, you go from "blank canvas" to "professional-looking UI" in an afternoon.

Tailwind CSS v4 — the dominant approach

Tailwind is utility-first CSS: instead of writing custom classes, you compose utilities directly in your markup.

<button class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors">
Click me
</button>

Tailwind v4 (released 2024–2025) brings:

  • Rust-based engine (much faster than v3).
  • CSS-first configuration (theme defined in CSS itself, not tailwind.config.js).
  • Native CSS features (cascade layers, container queries, color-mix).
  • Better integration with browser DevTools.

The "Tailwind is ugly" debate (largely settled):

Critics: "Long class strings are unreadable." Defenders: "It's actually faster to read and write than naming abstractions." By 2026 the dominant view is that Tailwind is fine — most teams that try it stay with it.

shadcn/ui — not a library, a collection

shadcn/ui is not an npm package. It's a CLI that copies React components into your project. The components use Radix UI primitives for accessibility and Tailwind for styling.

bunx shadcn@latest add button card input form dialog

This creates components/ui/button.tsx (etc.) in your project. You own the code; you can customize freely.

Why it took over:

  • Beautiful, accessible defaults.
  • No version lock-in (you copy the code).
  • Easy to customize (just edit the file).
  • Works perfectly with Tailwind and Next.js.

Almost every new React project in 2026 starts with shadcn/ui.

Worked example: from blank Next.js to professional UI in 5 minutes
bunx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
bunx shadcn@latest init
bunx shadcn@latest add button card input form dialog dropdown-menu

# Now you have professionally-designed components in components/ui/
# Use them like:
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';

export default function Home() {
return (
<Card>
<CardHeader>
<CardTitle>Hello, world</CardTitle>
</CardHeader>
<CardContent>
<Button>Click me</Button>
</CardContent>
</Card>
);
}

You now have a polished, accessible button and card without writing a line of CSS. This is dramatically faster than 5 years ago.

CSS Modules

Locally-scoped CSS files. Class names are automatically prefixed to avoid global collisions.

// Button.tsx
import styles from './Button.module.css';
export const Button = () => <button className={styles.primary}>Click</button>;
/* Button.module.css */
.primary { background: blue; color: white; }

When to use: Teams that want regular CSS with scoping; non-Tailwind shops; gradual migration paths.

Vanilla Extract / Panda CSS

Type-safe CSS-in-JS at build time. You write CSS in TypeScript; it compiles to static CSS files.

import { style } from '@vanilla-extract/css';

export const button = style({
padding: '8px 16px',
background: 'blue',
':hover': { background: 'darkblue' },
});

When to use: Large teams that want type-safe theming and don't like Tailwind's utility approach.

Styled-Components / Emotion (runtime CSS-in-JS)

Popular in 2018–2022; falling out of favor by 2026. They don't play nicely with React Server Components (which can't run client-side JS to inject styles), and they have runtime performance costs.

Decision matrix

Project TypeRecommendation
New React appTailwind + shadcn/ui
Vue appTailwind
Design-system-heavy teamTailwind + custom components OR Vanilla Extract
Backend-heavy / minimal JSTailwind + handwritten HTML
Legacy migrationCSS Modules
Highlight: design tokens make Tailwind into a design system

A common worry: "If I write bg-blue-500 everywhere, what happens when I want to change the brand color?"

The answer: define design tokens in your Tailwind config (or CSS variables in Tailwind v4) and use semantic names — bg-primary, text-foreground, border-muted. Then you change the token in one place and everything updates. shadcn/ui ships with this pattern out of the box.

Common mistakes

Where people commonly trip up
  • Hardcoding raw Tailwind colors everywhere, then needing to rebrand. bg-blue-500 scattered across 300 components is a slow find-and-replace nightmare. Use design tokens (bg-primary, text-foreground) from day one — shadcn/ui ships them by default.
  • Treating shadcn/ui as an npm dependency. It isn't. The components are your code in components/ui/. Don't avoid editing them "to stay upgradable" — customizing is the whole point. There's nothing to upgrade.
  • Following a v3 Tailwind tutorial in v4. v4 moved config from tailwind.config.js into CSS (@theme, @import). Mixing the two breaks things subtly. Check the version on the docs site before copy-pasting setup steps.
  • Adding styled-components or Emotion to a new RSC project. Runtime CSS-in-JS needs client JS to inject styles — RSCs don't ship any. You'll get flash-of-unstyled-content and hydration mismatches. Use Tailwind, CSS Modules, or build-time CSS-in-JS (Vanilla Extract) instead.
  • Building a custom design system before you've shipped anything. Six weeks of token taxonomy and Storybook setup before a single user sees the product. Use shadcn/ui + Tailwind defaults, ship, then harden the system once you know what you actually need.

Page checkpoint

Checkpoint Quiz

Did styling stick?

Required

What's next

→ Continue to Build Tools — the engines that turn your TypeScript and Tailwind into something browsers can load.