Using Shadcn UI without a Tailwind Config File

October 22, 2024

Edit: The Tailwind v4 Beta is out along with new Docs 🎉

The upcoming release of Tailwind CSS v4, we can return to styling that, at its core, emphasizes CSS-native solutions. This approach enables maintainable and performant styling systems that work seamlessly with Shadcn UI components.

Unlike with previous Tailwind versions we no longer need to use a JavaScript configuration file. Instead, we can rely on CSS variables and the new Tailwind CSS v4 directives to initialize Tailwind's functionality.

What we'll cover

Let's see how we could setup Shadcn UI components with Tailwind CSS v4 without using a tailwind.config.js file.

1. Installing Tailwind V4's dependencies: We'll install the latest release candidate of Tailwind CSS v4 and @tailwindcss/postcss.

2. Setting Up Tailwind V4 CSS Configuration: We'll establish the foundational setup that powers our modern Tailwind CSS v4 and Shadcn UI integration.

3. Adding custom colors to our Tailwind config: We'll define custom colors through native CSS variables, enabling powerful theming capabilities right out of the box.

4. Setting up Shadcn: We'll explore how to effectively utilize these components within our application, taking full advantage of Tailwind CSS v4's new features.

By the end, we'll be able to use Shadcn UI components in our Next.js 15 application with Tailwind CSS v4 styles.

<div className="flex items-center space-x-2">
  <Switch /> <span>Shadcn UI Switch</span>
</div>
Shadcn UI Switch

Installing the necessary dependencies

Before we can setup Tailwind, we have to install the latest release candidate of Tailwind CSS v4 and @tailwindcss/postcss

pnpm add tailwindcss@next tailwindcss/postcss@next

We're assuming you've configured PostCSS in your project. With Next.js, all this requires is a postcss.config.js file in the root of your project.

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
  },
};

If you are using Vite, follow Tailwind's documentation on how to setup PostCSS with Vite.

Why do we still need @tailwindcss/postcss?

The tailwindcss package provides the Tailwind CSS framework. The @tailwindcss/postcss package is a plugin that allows you to use Tailwind CSS with the PostCSS CSS transformation tool.

As of publishing this post, the Next.js documentation still reccomends you install tailwind with it's default PostCSS configration.

In Tailwind CSS v4, the Tailwind now published it's own CSS parsing CLI, @tailwindcss/cli. It's still in Alpha so I've opted to use the tailwindcss/postcss package for now.

Setting Up the CSS Configuration

We're assuming your bundler of choice supports CSS imports, like Vite or Next.js. If you're using a different bundler, you may need to configure CSS imports.

The global CSS configuration in this setup takes a CSS-first approach, departing from the traditional JavaScript-based Tailwind configuration. By utilizing the app/globals.css file as our central styling hub, we establish a robust foundation for our application's styling system.

To get started, import tailwindcss in a global stylesshet, globals.css, in your app directory:

// app/globals.css
@import "tailwindcss";
/* ... */

Then, make sure you import this CSS file in your application root, like layout.tsx.

// app/layout.tsx
import "./global.css";

This will configure all the tailwind default styles and base utilities for your application. You can now use Tailwind CSS classes in your components.

// app/layout.tsx
import "./global.css";
// ...
export default function Layout({ children }) {
  return <div className="bg-gray-400">{children}</div>;
}

Custom Colors and Utilities

With Tailwind CSS v4's new approach, custom colors and utilities are defined through native CSS variables and then made available to other tailwind directives and layers.

@import "tailwindcss";

@theme {
  --color-mint-green: oklch(83.66% 0.125 176.45);
  --color-baby-blue: oklch(85.61% 0.094 225.87);
}

You can then use these custom colors in your components:

<div className="bg-mint-green"></div>

Shadcn UI Component Installation

Adding the Shadcn UI Colors and Variables to Tailwind

To use Shadcn's color scheme, we need to update our globals.css file to include the Shadcn UI CSS variables.

// app/globals.css
@import "tailwindcss";

/* Define the Shadcn UI CSS Variables */
:root {
  --background: hsl(224 71% 4%);
  --foreground: hsl(213 31% 91%);

  --muted: hsl(223 47% 11%);
  --muted-foreground: hsl(215.4 16.3% 56.9%);

  --accent: hsl(216 34% 17%);
  --accent-foreground: hsl(210 40% 98%);

  --popover: hsl(224 71% 4%);
  --popover-foreground: hsl(215 20.2% 65.1%);

  --border: hsl(216 34% 17%);
  --input: hsl(216 34% 17%);

  --card: hsl(224 71% 4%);
  --card-foreground: hsl(213 31% 91%);

  --primary: hsl(210 40% 98%);
  --primary-foreground: hsl(222.2 47.4% 1.2%);

  --secondary: hsl(222.2 47.4% 11.2%);
  --secondary-foreground: hsl(210 40% 98%);

  --destructive: hsl(0 63% 31%);
  --destructive-foreground: hsl(210 40% 98%);

  --ring: hsl(216 34% 17%);
}

Then, instead of adding the colors to a tailwind.config.ts file, we're going to use the @theme directive in our global.css.

The @theme directive registers the Shadcn UI CSS variables with Tailwind.

// app/globals.css
/* ... */
@theme {
  --color-mint-green: oklch(83.66% 0.125 176.45);
  --color-baby-blue: oklch(85.61% 0.094 225.87);
  /* Shadcn UI */
  --color-mint-green: oklch(83.66% 0.125 176.45);
  --color-baby-blue: oklch(85.61% 0.094 225.87);
  /* Shadcn UI */
  --radius: 0.5rem;
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-background: var(--background);
  --color-foreground: var(--foreground);

  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);

  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);

  --color-destructive: var(--destructive);
  --color-destructive-foreground: var(--destructive-foreground);

  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);

  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);

  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);

  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);

  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);

  --font-family-poppins: var(--font-poppins);
  --font-family-inter: var(--font-inter);

  --animate-accordion-down: accordion-down 0.2s ease-out;
  --animate-accordion-up: accordion-up 0.2s ease-out;

  @keyframes accordion-down {
    from {
      height: 0;
    }

    to {
      height: var(--radix-accordion-content-height);
    }
  }

  @keyframes accordion-up {
    from {
      height: var(--radix-accordion-content-height);
    }

    to {
      height: "0";
    }
  }
}

All togehter our globals.css file should look like this:

@import "tailwindcss";

/* Define the Shadcn UI CSS Variables */
:root {
  --background: hsl(224 71% 4%);
  --foreground: hsl(213 31% 91%);
  /* ... */
}

/* Add the Shadcn CSS variables to our theme layer */
@theme {
  --color-mint-green: oklch(83.66% 0.125 176.45);
  --color-baby-blue: oklch(85.61% 0.094 225.87);
  /* Shadcn UI */
  --radius: 0.5rem;
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  /* ... */
}

Now all of the Shadcn UI CSS variables are available to use in our components.

Installing Shadcn UI Components

To install Shadcn UI components to your project, we'll need to manually copy and pase them into your components directory.

Why not use the Shadcn CLI?

Using Tailwind CSS v4 without a JS config file means that the traditional Shadcn UI CLI installation method, which relied on tailwind.config.js modifications, is not possible until the CLI is updated.

This process involves creating appropriate directory structures, managing dependencies, and setting up component files in a way that maintains consistency and scalability. You can refer to their suggested best practices for component installation.

We are going to copy/paste the <Switch> component from the Shadcn UI documentation and integrate it into our project in /components/ui/Switch.tsx.

We'll also need to install the radix-ui dependency.

pnpm add @radix-ui/react-switch

Once you've added the component and it's dependencies, you can import and use it in your project.

import { Switch } from "./components/ui/Switch";

export default function MySwitch() {
  return (
    <div className="flex items-center space-x-2">
      <Switch /> <span>Shadcn UI Switch</span>
    </div>
  );
}
Shadcn UI Switch

Frequently asked questions

Why are some components not working correctly?

Tailwind v4 changes some previously default behavior and styles (like default border colors). Some Shadcn component at the time of writing still rely on the old defaults. Depending on how much or how little you've customized them, you might need to manually update styles and classnames to match the new v4 spec.

If you run into trouble, try using the newly released codemod for update the class names.

What about light/dark mode?

Tailwind v4 changes the the dark variant strategy defaults. Supporting this takes a little bit of additional configuration if you were previously using a selector based approach.

You can follow along on this GitHub issue as a reference for using the selector approach.

Conclusion

Thanks to Tailwind V4 it's never been easier to add Tailwind to a project. Combined with the ease-of-use of Shadcn UI components, you can quickly build modern, accessible, and performant web applications.

Hopefully you can use this post as springboard to migrate your own projects to this new setup!

If there's anything you'd like to see in this or a future post, let me know on Twitter @luqven.