Integrating Astro 5, Storybook 9, Vite 7, and Tailwind 3 🐇🕳️
Ingo Steinke, web developer

Ingo Steinke, web developer @ingosteinke

About: Ingo Steinke is a web developer focusing on front-end web development to create and improve websites and make the web more accessible, sustainable, and user-friendly.

Joined:
Sep 21, 2019

Integrating Astro 5, Storybook 9, Vite 7, and Tailwind 3 🐇🕳️

Publish Date: Aug 8
7 7

I wrote this post hoping that someone adds a simpler best-practice configuration solution that I must have overlooked. But let's start at the beginning. Astro is a meta-framework to build static websites with optional interactive islands in React, Svelte, Solid or anything similar. Storybook is a web app to preview modular design system components. Vite is a modern bundler alternative to Webpack.

How to use Storybook with Astro?

As Matt Fantinel pointed out, you don't. Storybook can't understand Astro, but it understands JSX/TSX, and Astro can render React/Solid/Svelte components to scriptless static HTML when we omit the client: directive. So, we can write all of our components in React, even those that only contain static content. Thanks to Antonio Pitasi for pointing that out in Astro: writing static websites like it’s 2023.

We can provide example content in our stories files, and we can pass content from Astro's content collections to our React components. So far, so good.

Integrating Storybook, Vite, and Tailwind 3

According to the official documentation, integrating Tailwind and Storybook should be as easy as adding import '../src/styles/global.css'; to our .storybook/preview.ts and only configuring PostCSS if we don't use Vite. Honestly, the linked documentation doesn't explicitly mention React or Astro.
Maybe that's a problem.

Anyway, this approach silently failed without any error message or debug details when using Astro 5, Astro-Tailwind 6, Storybook-React-Vite 9, and Tailwind 3.3 together with PostCSS 8, as an implicit peer dependency of all of Astro, React, and Tailwind, as npm list postcss tells us. Npm lists two different Vite versions, however, vite@6.3.5 used two times, by astro@5.12.8 and @astrojs/react@4.3.0, vs. vite@7.0.6 (deduped), used 8x by everything else, including @vitejs/plugin-react@4.7.0 which was in turn required by @astrojs/react@4.3.0.
Maybe that's a problem.

Screenshot of npm list vite

PostCSS gets required 15 times, but it's always the same version.

Screenshot: npm list postcss output

Despite both Tailwind CSS and Storybook (or, more precisely, Storybook's React-Vite, via Vite) require PostCSS, Storybook still doesn't seem to use it as expected.

Double-Checking before Posting

Before asking myself in which project I could possibly open a GitHub issue, or how to provide a minimal reproducible example for asking on StackOverflow, let's double-check documentation, matching versions, and add the missing explicit PostCSS cconfiguration (that we don't need for npm run dev).

Double-checking step by step:

The path to global.css is correct. Changing it to a project-rooted /src/styles/global.css doesn't change anything. Specifying a nonexistant paht like src/global.css throws a fatal errror.

To make sure that .storybook/preview.ts isn't just checked but really used, I added a console.log('storybook preview ts executed'); below the import. Its output shows in my browser console.

It is correct to use Tailwind 3 (not Tailwind 4) with Astro 5, and all of our libraries use the same PostCSS version without explicit pinning. Tailwind 3.3 is the latest stable Tailwind 3 release. Astro and Vite are up to date as well.

Manual Configuration of Storybook + Tailwind + PostCSS

The documentation implies that for integrating Tailwind's PostCSS compilation, when using Vite, we can simply skip to the next step, and, in case of a failing Webpack configuration scripts:

For manual configuration instructions for PostCSS, you can refer to the documentation here.

Only that the documentation doesn't provide any manual configuration instructions for PostCSS anymore, not for Webpack and not for Vite either. AI assistants like Claude or Perplexity unanimously suggest adding the following explicit PostCSS configuration.

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};
Enter fullscreen mode Exit fullscreen mode

In my case, adding the PostCSS configuration above leads to an internal server error (HTTP Status 500) causing an infinite spinner icon in the Storybook preview. However, running Storybook with -loglevel verbose --debug reveals no errors and no other helpful details.

My Astro dev server (npm run dev) and production build (npm run build) still work flawlessly inclusing my global Tailwind CSS styles.

Solution 🤷

The solution: add the function that I failed to see last week.

I already got it right, mostly, but still missing the crucial viteFinal function in my .storybook/main.ts configuration.

My interim work-in-progress code is now fixed!

A short check list:

  • [x] tailwindcss and autoprefixer in package.json explicitly, not only as peer dependencies of other packages,
  • (@storybook/addon-postcss in package.json is not necessary)
  • [x] postcss.config.js defining two plugins: tailwindcss: {}, autoprefixer: {}
  • [x] .storybook/preview.ts importing the global Tailwind 3 styles: import '../src/styles/global.css';
  • [x] .storybook/main.ts configuration defining a viteFinal configuration, again explicitly requiring tailwindcss and autoprefixer.

Here are the relevant lines in package.json ...

  "dependencies": {
    "@astrojs/react": "^4.3.0",
    "@astrojs/ts-plugin": "^1.10.4",
    "astro": "^5.12.8",
    "autoprefixer": "^10.4.17",
    "postcss": "^8.4.35",
    "tailwindcss": "~3.3.7"
  },
  "devDependencies": {
    "@astrojs/tailwind": "^6.0.2",
    "@storybook/addon-a11y": "^9.1.1",
    "@storybook/addon-docs": "^9.1.1",
    "@storybook/addon-vitest": "^9.1.1",
    "@storybook/react-vite": "^9.1.1",
    "storybook": "^9.1.1",
Enter fullscreen mode Exit fullscreen mode

... and the essential .storybook/main.ts:

import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';

const config: StorybookConfig = {
    'stories': [
        '../src/**/*.mdx',
        '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'
    ],
    'addons': [
    '@storybook/addon-docs',
    '@storybook/addon-a11y',
    '@storybook/addon-vitest',
  ],
    'framework': {
        'name': '@storybook/react-vite',
        'options': {}
    },
  async viteFinal(config) {
    return mergeConfig(config, {
      css: {
        postcss: {
          plugins: [
            require('tailwindcss'),
            require('autoprefixer'),
          ],
        },
      },
    });
  },
};
export default config;
Enter fullscreen mode Exit fullscreen mode

Comments 7 total

  • Lucas Braga
    Lucas BragaAug 8, 2025

    🚀 Hello, developers!

    You’ve just received a VIP invitation to join one of the biggest tech events of the year — the Global Dev Summit 2025 — with both in-person and online access, fully covered (ticket, travel, and accommodation for the on-site option).

    🎯 Why you should join:

    • Talks from international tech experts
    • Exclusive technical workshops
    • Networking with developers worldwide
    • Latest trends in software, cloud, security, and AI

    💎 Special VIP Bonus

    All VIP attendees will also receive:

    • 🧥 AWS T-shirt
    • 🥤 AWS Branded Cup
    • 💳 $100 Gift Voucher

    ✅ How to claim your VIP spot

    1. Visit: globaldevsummit.com/
    2. Check the agenda and choose your mode (in-person or online)
    3. Activate your free VIP ticket and secure your gifts

    📅 Date: See official website

    📍 Format: Hybrid (On-site + Online)

    🔥 Secure your VIP pass now at Global Dev Summit 2025 and enjoy the event + exclusive AWS gifts!


    PS: Invitation for developers and tech professionals passionate about innovation.

  • Ingo Steinke, web developer
    Ingo Steinke, web developerAug 12, 2025

    I updated and added the missing details.

  • Sascha Klatt
    Sascha KlattAug 14, 2025

    Quite sad Storybook still doesn't support Astro out of the box...

    • Ingo Steinke, web developer
      Ingo Steinke, web developerAug 14, 2025

      Absolutely. Writing every component in JSX/TSX is no nice workaround. Maybe I should consider an alternative like Histoire?

      • Sascha Klatt
        Sascha KlattAug 18, 2025

        Hmm... looking at their plugins Histoire doesn't support Astro files as well, right? Seems that you'd also need to choose a JS framework for it.

      • Sascha Klatt
        Sascha KlattAug 18, 2025

        Just came across Astrobook. Haven't tried it out yet, but maybe it could be interesting.

  • Ingo Steinke, web developer
    Ingo Steinke, web developerAug 27, 2025

    ... and daisyUI v4 (not the latest v5), just for completeness sake.

    Tailwind v3 (required by Astro 5.12) implies daisyUI v4 (not the latest v5).

Add comment