Styling
Astro component scoped styles work automatically — Storybook Astro handles them during rendering. But global styles, CSS utility frameworks, and fonts loaded outside your components (e.g. in a layout’s <head>) require manual setup.
Global CSS
Section titled “Global CSS”Most Astro projects have a global stylesheet imported in a layout file:
---import '../styles/global.css';---Storybook doesn’t render your layout, so you need to import global styles in the Storybook preview. Create a .storybook/preview.css file:
@import '../src/styles/global.css';Then import it in .storybook/preview.js:
import './preview.css';
const preview = { parameters: { controls: { matchers: { color: /(background|color)$/i, date: /Date$/i, }, }, },};export default preview;CSS utility frameworks
Section titled “CSS utility frameworks”CSS frameworks like UnoCSS and Tailwind CSS are typically configured as Astro integrations, but their Vite plugins may not be automatically available in Storybook’s build pipeline. You can add them directly using viteFinal in .storybook/main.js.
UnoCSS
Section titled “UnoCSS”import UnoCSS from 'unocss/vite';
export default { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], framework: { name: '@storybook-astro/framework', options: {}, }, async viteFinal(config) { config.plugins = config.plugins || []; config.plugins.push(UnoCSS()); return config; },};Then import UnoCSS’s generated stylesheet in .storybook/preview.js:
import 'virtual:uno.css';import './preview.css';UnoCSS reads your project’s uno.config.ts automatically, so your presets (e.g. presetWind, presetIcons, presetTypography) will apply.
Tailwind CSS
Section titled “Tailwind CSS”For Tailwind CSS v4+ (which uses a Vite plugin):
import tailwindcss from '@tailwindcss/vite';
export default { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], framework: { name: '@storybook-astro/framework', options: {}, }, async viteFinal(config) { config.plugins = config.plugins || []; config.plugins.push(tailwindcss()); return config; },};For Tailwind CSS v3 (which uses PostCSS), no viteFinal changes are needed — just ensure your global CSS with @tailwind directives is imported in .storybook/preview.css and your postcss.config.js is in place.
Fonts loaded via Astro components (e.g. in <head> through a layout) won’t be available in stories because Storybook renders components in isolation, without your page layout.
Add @font-face declarations directly in .storybook/preview.css:
@import '../src/styles/global.css';
@font-face { font-family: 'CustomFont'; font-style: normal; font-display: swap; src: url('/fonts/custom-font.woff2') format('woff2');}
.custom-font { font-family: 'CustomFont', sans-serif;}Static assets
Section titled “Static assets”If your font files or other assets live in the public/ directory, tell Storybook to serve them with staticDirs:
export default { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], staticDirs: ['../public'], framework: { name: '@storybook-astro/framework', options: {}, },};This makes files in public/ available at the root URL path — e.g. public/fonts/outfit.ttf is served at /fonts/outfit.ttf, matching how Astro serves them.
Full example
Section titled “Full example”Here’s a complete setup for a project using UnoCSS with local fonts:
import UnoCSS from 'unocss/vite';
export default { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], staticDirs: ['../public'], framework: { name: '@storybook-astro/framework', options: {}, }, async viteFinal(config) { config.plugins = config.plugins || []; config.plugins.push(UnoCSS()); return config; },};import 'virtual:uno.css';import './preview.css';
const preview = { parameters: { controls: { matchers: { color: /(background|color)$/i, date: /Date$/i, }, }, },};export default preview;@import '../src/styles/global.css';
@font-face { font-family: 'Poppins'; font-style: normal; font-display: swap; src: url('/fonts/poppins.ttf') format('truetype');}
.poppins { font-family: 'Poppins', sans-serif; }