Skip to content

shadcn.io is an independent project built on shadcn/ui

Gatsby

Use shadcn.io components in a Gatsby site: move it to Tailwind CSS v4 with PostCSS, alias @/ in webpack, check React, then run init and add components.

Gatsby takes more setup than the other frameworks: its starter installs Tailwind CSS v3, which can't build these components, and its webpack doesn't read TypeScript's aliases. Both are fixable in a few files. For a new site, Next.js or Astro start with everything in place.

Set up a Gatsby site

Create the site, if you need one

npm init gatsby

Answer TypeScript when it asks for a language: the components are .tsx files. Skip the styling system question; the next step sets up Tailwind CSS v4.

Set up Tailwind CSS v4 with PostCSS

bun add tailwindcss @tailwindcss/postcss postcss gatsby-plugin-postcss

Add the plugin to gatsby-config.ts:

gatsby-config.ts
import type { GatsbyConfig } from "gatsby";

const config: GatsbyConfig = {
  plugins: ["gatsby-plugin-postcss"],
};

export default config;

Create postcss.config.js at the root:

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

Create src/styles/global.css and load it on every page from gatsby-browser.tsx:

src/styles/global.css
@import "tailwindcss";
gatsby-browser.tsx
import "./src/styles/global.css";

A site that already has Tailwind CSS v3 can run npx @tailwindcss/upgrade instead: it moves the config, the PostCSS plugin and the stylesheet to v4. Tailwind's Gatsby guide (opens in a new tab) has the same steps.

Add the @ alias for TypeScript and webpack

TypeScript reads the alias from tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Gatsby's webpack doesn't, so repeat it in gatsby-node.ts (create the file if it's missing):

gatsby-node.ts
import path from "node:path";
import type { GatsbyNode } from "gatsby";

export const onCreateWebpackConfig: GatsbyNode["onCreateWebpackConfig"] = ({
  actions,
}) => {
  actions.setWebpackConfig({
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
      },
    },
  });
};

One @ alias covers every import the components use: @/components/ui, @/lib/utils and @/hooks.

Check React

npm ls react

The components take ref as a regular prop, the way React 19 passes it. On React 18 they render and work, but a ref you pass to one doesn't reach its element.

Run init

shadcn CLILocked
Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

The CLI detects Gatsby from gatsby-config and finds src/styles/global.css by its @import "tailwindcss" line: that's where the theme goes.

Add a component and use it

shadcn CLILocked
Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
src/pages/index.tsx
import { Button } from "@/components/ui/button";

export default function IndexPage() {
  return (
    <main className="flex min-h-svh items-center justify-center">
      <Button>Click me</Button>
    </main>
  );
}

FAQ

Can I keep Tailwind CSS v3 in my Gatsby site?

Not for these components. They and the theme rely on v4: @theme, @custom-variant and CSS variables for every color. npx @tailwindcss/upgrade moves most sites over in one run.

Why does the build fail with “Can't resolve '@/components/ui/button'”?

The alias is only in tsconfig.json. Gatsby bundles with webpack, which needs its own alias: add onCreateWebpackConfig to gatsby-node.ts as in step 3, then restart gatsby develop.

My site is JavaScript. Can I still use the components?

The files the CLI adds are TypeScript (.tsx). Gatsby compiles TypeScript out of the box, so they run in a JavaScript site; add a tsconfig.json with the @/* alias for the CLI to read.

Do the components work with Gatsby's static rendering?

Yes. Gatsby renders each page to HTML at build time, then hydrates it. Components that need the browser (overlays, menus) do their work after hydration, so nothing touches window during the build.

What happens on React 18?

Most things work, but a ref you pass to a component doesn't reach its element: React 18 strips ref from a function component's props, and the components read it as a prop the way React 19 does. Check npm ls react before you rely on refs.

Where should the global CSS be imported?

In gatsby-browser.tsx, so it loads on every page. Import it in gatsby-ssr.tsx too if you want it in the server-rendered HTML before the bundle loads.

Should I start a new site on Gatsby?

Pick based on what the site needs, but for these components Next.js and Astro start with Tailwind CSS v4, React 19 and the alias in place, and init -t creates either in one command.

How do I add dark mode in Gatsby?

Toggle a .dark class on <html>. Set it before React hydrates, with an inline script added through onRenderBody in gatsby-ssr.tsx, so the page doesn't flash light first.