DEV Community

Ingo Steinke, web developer
Ingo Steinke, web developer Subscriber

Posted on • Edited on

Integrating Astro 5, Storybook 9, Vite 7, and Tailwind 3 πŸ‡πŸ•³οΈ

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

Top comments (6)

Collapse
 
saschaklatt profile image
Sascha Klatt

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

Collapse
 
ingosteinke profile image
Ingo Steinke, web developer

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

Collapse
 
saschaklatt profile image
Sascha Klatt

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

Collapse
 
saschaklatt profile image
Sascha Klatt

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.

Collapse
 
ingosteinke profile image
Ingo Steinke, web developer

... 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).

Collapse
 
ingosteinke profile image
Ingo Steinke, web developer

I updated and added the missing details.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.