Shared Component Library
The @storybook-astro/components package provides a shared library of Astro components and framework-specific implementations. This allows you to build components once and use them in Storybook, the website, integration examples, and your own projects.
What’s included
Section titled “What’s included”The shared library includes:
- Astro components: Pure
.astrofiles (Header, Footer, Card, Counter, Accordion, CodeTabs, etc.) - Framework implementations: React, Vue, Svelte, Preact, Solid, and Alpine.js versions of common components
- Test fixtures: Components pre-configured for testing across multiple frameworks
Using shared components in stories
Section titled “Using shared components in stories”Instead of duplicating components in each integration example, import from @storybook-astro/components:
// Before: Duplicated in each integration exampleimport Card from './Card.astro';
// After: Shared componentimport Card from '@storybook-astro/components/Card/astro/Card.astro';Directory structure
Section titled “Directory structure”Components are organized by type:
@storybook-astro/components/├── Card/│ └── astro/Card.astro├── Header/│ └── astro/Header.astro├── Counter/│ ├── astro/Counter.astro│ ├── react/Counter.jsx│ ├── solid/Counter.tsx│ └── vue/Counter.vue└── CodeTabs/ ├── astro/CodeTabs.astro ├── react/CodeTabs.jsx ├── solid/CodeTabs.tsx └── vue/CodeTabs.vueFramework-specific components
Section titled “Framework-specific components”Many components include framework-specific implementations. Access them via the framework path:
// Astro versionimport Counter from '@storybook-astro/components/Counter/astro/Counter.astro';
// React versionimport Counter from '@storybook-astro/components/Counter/react/Counter.jsx';
// Solid versionimport Counter from '@storybook-astro/components/Counter/solid/Counter.tsx';
// Vue versionimport Counter from '@storybook-astro/components/Counter/vue/Counter.vue';In Storybook stories, use the parameters.renderer setting to render framework components:
import Counter from '@storybook-astro/components/Counter/react/Counter.jsx';
export default { title: 'React/Counter', component: Counter, parameters: { renderer: 'react', // Tell Storybook to use React renderer },};
export const Default = {};CodeTabs component
Section titled “CodeTabs component”The CodeTabs component demonstrates multi-framework hydration by rendering code snippets in multiple package manager formats (npm, yarn, pnpm, bun).
Astro version
Section titled “Astro version”import CodeTabs from '@storybook-astro/components/CodeTabs/astro/CodeTabs.astro';
export default { title: 'Components/Code Installation', component: CodeTabs, args: { framework: 'react', // react, solid, preact, svelte, vue, alpine },};
export const Default = { args: { framework: 'react' },};
export const Solid = { args: { framework: 'solid' },};Framework versions
Section titled “Framework versions”Framework implementations (React, Vue, Svelte, Solid, Preact) render tabs with client-side interactivity:
// React version with client-side tab switchingimport CodeTabs from '@storybook-astro/components/CodeTabs/react/CodeTabs.jsx';
export default { title: 'React/Code Installation', component: CodeTabs, parameters: { renderer: 'react' },};
export const Default = {};Benefits
Section titled “Benefits”- Single source of truth — Fix bugs once, benefit everywhere
- Testing coverage — Test components across Astro 5, Astro 6, and multiple frameworks
- Documentation — Components serve as examples for your docs
- Consistency — Same components in Storybook, website, and integration examples
- Reduced duplication — Stop copying components between projects
Using in your own projects
Section titled “Using in your own projects”You can also use shared components in your own Astro applications:
npm install @storybook-astro/componentsThen import components:
// In your Astro layout or componentimport Header from '@storybook-astro/components/Header/astro/Header.astro';import Footer from '@storybook-astro/components/Footer/astro/Footer.astro';
---
<Header /><main>...</main><Footer />Component configuration
Section titled “Component configuration”In Storybook
Section titled “In Storybook”Configure stories to include shared components:
export default { stories: [ '../src/**/*.stories.@(js|jsx|ts|tsx)', // Include shared component stories getAbsolutePath('@storybook-astro/components') + '/src/*.mdx', getAbsolutePath('@storybook-astro/components') + '/src/**/*.stories.@(js|jsx|mjs|ts|tsx)', ],};In tests
Section titled “In tests”Test shared components with portable stories:
import { screen } from '@testing-library/dom';import { test, expect } from 'vitest';import { composeStories, renderStory } from '@storybook-astro/framework/testing';import * as stories from '@storybook-astro/components/Card/astro/Card.stories.jsx';
const { Default } = composeStories(stories);
test('Card renders correctly', async () => { await renderStory(Default); expect(screen.getByText('Default title')).toBeInTheDocument();});Testing across frameworks
Section titled “Testing across frameworks”One of the main benefits of the shared library is the ability to test the same component concept across multiple frameworks.
Astro component test
Section titled “Astro component test”import { composeStories, renderStory } from '@storybook-astro/framework/testing';import * as astroStories from '@storybook-astro/components/Counter/astro/Counter.stories.jsx';
const { Default } = composeStories(astroStories);
test('Astro Counter renders', async () => { await renderStory(Default); expect(screen.getByTestId('vanilla-counter')).toBeInTheDocument();});React component test
Section titled “React component test”import { render, screen } from '@testing-library/react';import Counter from '@storybook-astro/components/Counter/react/Counter.jsx';
test('React Counter renders', () => { render(<Counter />); expect(screen.getByText('React counter: 1')).toBeInTheDocument();});Solid component test
Section titled “Solid component test”import { render, screen } from 'solid-testing-library';import Counter from '@storybook-astro/components/Counter/solid/Counter.tsx';
test('Solid Counter renders', () => { render(() => <Counter />); expect(screen.getByText('Solid counter: 1')).toBeInTheDocument();});Contributing components
Section titled “Contributing components”To add new components to the shared library:
- Create the Astro version in
packages/components/src/ComponentName/astro/ComponentName.astro - Create the story file in the same directory with
.stories.jsx - Add framework versions as needed (React, Vue, Solid, etc.)
- Add tests with
.test.tsfiles - Document the component in a README or JSDoc comments
Components are automatically available in Storybook and your project after running npm install.
Troubleshooting
Section titled “Troubleshooting”Component not found
Section titled “Component not found”Ensure the import path matches the directory structure:
// ❌ Wrong: might not existimport Button from '@storybook-astro/components/Button/Button.astro';
// ✅ Correct: verify the path existsimport Button from '@storybook-astro/components/Button/astro/Button.astro';Framework component not rendering
Section titled “Framework component not rendering”Verify you’re using the correct parameters.renderer:
// ❌ Wrong rendererexport default { component: ReactCounter, parameters: { renderer: 'vue' }, // Should be 'react'};
// ✅ Correctexport default { component: ReactCounter, parameters: { renderer: 'react' },};Storybook not finding stories
Section titled “Storybook not finding stories”Update .storybook/main.js to include the shared component stories path:
stories: [ '../src/**/*.stories.@(js|jsx|ts|tsx)', // Add this line: getAbsolutePath('@storybook-astro/components') + '/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',],