crumpled paper texture























Why I Build With shadcn/ui

Quincy Pitsi | 2025-09-27

Building frontends these days can feel a bit overwhelming with options like Material UI, Chakra UI, Ant Design and countless others, it’s easy to assume that choosing a polished component library will automatically speed up your development. Install a package, pick a theme, and you’re sorted. In practice, you often end up fighting the library instead of building the thing you actually care about. That’s where shadcn/ui feels different. This post looks at why shadcn/ui fits so well with Next.js 15 and Tailwind CSS 4, and why I prefer its copy-and-own model for iterating and building frontends quickly for side projects and POC's.

AI Study Tools


Not a typical component library

The first surprise with shadcn/ui is that you do not install it as a normal dependency. There is no single package in node_modules that controls all your UI. Instead you run a CLI command and copy actual component source files into your project.

npx shadcn-ui@latest init
npx shadcn-ui@latest add button card dialog

After that the components live in your repository. They are written in TypeScript, styled with Tailwind and structured around Radix primitives. If you want to change a Dialog, you open dialog.tsx and edit it like any other component.

This small shift changes the relationship between you and your UI kit. You are not working around a black box. You own the code.


Why the Tailwind and Radix combination works

Shadcn/ui leans on two tools that already have strong adoption in modern React projects:

  • Radix UI for behaviour and accessibility
  • Tailwind CSS for styling

Radix gives you headless primitives that handle keyboard support, ARIA attributes and focus management. Tailwind gives you utility classes that keep styling close to the markup. Shadcn brings these together into ready-made components.

You get:

  • Accessible markup out of the box
  • Tailwind classes that you can read and adjust quickly
  • Clear structure that is easy to teach to a new developer who just joined the team

When you are working on a product for a local business in Sandton or a student portal for a university, that clarity saves time. A junior developer can inspect a Button component, see the Tailwind classes and adapt them without hunting through a theme object.


Design systems that do not feel locked in

Traditional libraries give you a theme file and a list of props for customisation. You can only change what the library exposes. When design requirements shift, you either stack overrides on top of overrides, or you fork the library.

With shadcn/ui:

  • Your team can treat each component as a starting point, not a fixed shape.
  • You can align the components with your internal design tokens.
  • You decide how aggressively you track upstream changes.

If the design system at your company in Gauteng changes button radiuses, you update one file and it is done. There is no need to wait for a library update or to dig through GitHub issues to see if someone else asked for the same thing.

You also only include the components you actually use. If your project never needs a Combobox, it never enters the bundle.


New structural components

Recent releases of shadcn/ui added more structural components that sit above the low-level primitives. These are not just pretty wrappers. They encode patterns that show up in many apps:

  • Field groups a label, description, error message and input into one unit.
  • Input Group and Button Group manage sets of related controls.
  • Spinner provides a shared loading pattern for buttons, forms and overlays.
  • Small utilities such as Kbd, Item and Empty keep micro-patterns like keyboard hints and empty states consistent.

Instead of rewriting the same layout and ARIA attributes for every form field, you rely on a Field component that already captures good practice.


How it fits with Next.js 15 and Tailwind CSS 4

Next.js 15 and Tailwind CSS 4 give shadcn/ui a solid foundation.

  • Next.js 15 adds mature routing, React Server Components support and an application structure that suits both marketing sites and data-heavy tools.
  • Tailwind CSS 4 introduces a token-based theming approach using the @theme directive so your colour and spacing decisions live in CSS, not just in a JavaScript config.

A typical stack looks like this:

  • Next.js 15 for routing and data fetching
  • Tailwind CSS 4 for design tokens and utilities
  • Shadcn/ui for component structure
  • Radix for low-level behaviour

You might define brand tokens like this:

@theme {
  --color-primary: #1d4ed8;
  --color-primary-foreground: #ffffff;
}

Then connect them to shadcn/ui by adjusting Tailwind classes in your Button and Card components. If a client in Durban wants a different palette, you update the tokens and a few classes instead of rewriting a theme object deep inside a library.


When shadcn/ui is a good fit

Shadcn/ui tends to work well when:

  • You need to build and iterate quickly.
  • Building an MVP or POC.
  • Your comfortable editing TypeScript and Tailwind.
  • You want to keep accessibility and structure in the same codebase as your business logic.

A small example: setting up a layout with shadcn/ui

Here is a minimal layout using shadcn/ui components in a Next.js project:

import { Button } from "@/components/ui/button";
import { Card, CardHeader, CardContent } from "@/components/ui/card";

export default function DashboardPage() {
  return (
    <main className="min-h-screen bg-background text-foreground">
      <section className="mx-auto flex max-w-5xl flex-col gap-6 px-4 py-10">
        <header className="flex items-center justify-between">
          <h1 className="text-2xl font-semibold">
            Client Accounts
          </h1>
          <Button>
            Add client
          </Button>
        </header>

        <Card>
          <CardHeader>
            <h2 className="text-lg font-medium">
              Overview
            </h2>
          </CardHeader>
          <CardContent>
            <p className="text-sm text-muted-foreground">
              Here you can see current balances, trends and account status for your clients.
            </p>
          </CardContent>
        </Card>
      </section>
    </main>
  );
}

The code is ordinary React. The styling is plain Tailwind. The components are yours.


Why I keep choosing shadcn/ui

  • I get components that already respect accessibility.
  • I keep styling in Tailwind, close to the TSX/JSX components.
  • I can adapt patterns to match each product without rewriting everything from scratch.

If you find yourself wrestling with your component library instead of shipping features, try shadcn/ui on your next Next.js and Tailwind project. Copy a few components in, connect them to your theme tokens and see how it feels to truly own your UI.

Always learning. Always Curious
Copyright © 2025 Quincy Pitsi. All rights reserved.