Astrobook is a UI component playground that supports multiple frameworks including React, Vue, Preact, Svelte, Solid, Lit, and Astro. It offers a unified environment to develop, test, and showcase components.
-
An example of using multiple UI rendering frameworks (React, Preact, Vue, Svelte, Solid, Lit, Astro) with Astrobook.
Online demo: astrobook.pages.dev
-
An example of using custom
<head>
tags with Astrobook. -
An example that shows how to add Astrobook into an existing Astro project.
-
An example of using TailwindCSS with Astrobook.
-
An example of using UnoCSS with Astrobook.
-
An example of using PandaCSS with Astrobook.
Note
Astrobook supports various frameworks. We use React as an example here. Check the Astro docs for other integrations.
-
Install the packages
npm install astro @astrojs/react astrobook
-
Create
astro.config.mjs
and add theastrobook
integration// astro.config.mjs import { defineConfig } from 'astro/config' import react from '@astrojs/react' import astrobook from 'astrobook' // https://astro.build/config export default defineConfig({ integrations: [react(), astrobook()], })
-
Add scripts to your
package.json
"scripts": { "dev": "astro dev", "build": "astro build" }
-
Write stories. Astrobook scans all
.stories.{ts,tsx,js,jsx,mts,mjs}
files. It's compatible with a limited subset of Storybook's Component Story Format v3. In particular,args
anddecorators
properties are supported.// src/components/Button.stories.ts import { Button, type ButtonProps } from './Button.tsx' import { Container } from './Container.tsx' export default { component: Button, } export const PrimaryButton = { args: { variant: 'primary' } satisfies ButtonProps, } export const SecondaryButton = { args: { variant: 'secondary' } satisfies ButtonProps, }
-
Run
npm run dev
and openhttp://localhost:4321
to see your stories.
Decorators are objects that have a property for the component and the props that will be passed to it on render. This component must have a slot for children to be rendered. Currently, decorators only support styling changes and are not able to change a component's context or any client-side behaviors. Any decorators are rendered into HTML by Astro and sent to the client.
You can use decorators to wrap a component with a custom style.
For example, this is a React decorator that adds a green border to a component and an Astro decorator that adds a red border to a component.
// ReactGreenBorderDecorator.tsx
import type { ComponentChildren } from 'react'
export function GreenBorderDecorator({
width = 2,
children,
}: {
width?: number
children?: ComponentChildren
}) {
return <div style={{ border: `solid ${width}px green` }}>{children}</div>
}
<!-- AstroRedBorderDecorator.astro -->
<div style="border: solid 2px red;">
<slot />
</div>
In your stories, you can use the decorators like this:
// Button.stories.tsx
import { Button, type ButtonProps } from './Button.tsx'
import { GreenBorderDecorator } from './ReactGreenBorderDecorator.tsx'
import RedBorderDecorator from './AstroRedBorderDecorator.astro'
export default {
component: Button,
}
export const PrimaryButton = {
args: { variant: 'primary' } satisfies ButtonProps,
decorators: [
{ component: GreenBorderDecorator, props: { width: 10 } },
{ component: RedBorderDecorator },
],
}
This will render the button, wrapped in a red border, which is then wrapped in a green border.
You can use the directory
option to specify the directory to scan for stories. The default directory is current working directory.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
integrations: [
astrobook({
directory: 'src/components',
}),
/* ...other integrations */
],
})
You can run Astrobook as a standalone app. You can also add it to your existing Astro project. In the latter case, you can use the subpath
option to specify the subpath of Astrobook.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
integrations: [
astrobook({
subpath: '/playground',
}),
],
})
In the example above, Astrobook will be available at http://localhost:4321/playground
.
Notice that the subpath
option is relative to your Astro project's base path. For example, if you configure both Astro's base
and astrobook
's subpath
, like so:
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
base: '/docs',
integrations: [
astrobook({
subpath: '/playground',
}),
],
})
Your Astro project will be available at http://localhost:4321/docs
and Astrobook will be available at http://localhost:4321/docs/playground
.
You can customize the styles by using the css
option to specify the CSS files to be imported into your Astrobook site.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
integrations: [
astrobook({
css: [
// Relative path to your custom CSS file
'./src/styles/custom.css',
],
}),
],
})
You can further customize your Astrobook project by providing a custom head
options. It's a path to an Astro component that includes custom tags to the <head>
of your Astrobook site. It should only include elements permitted inside <head>
, like <link>
, <style>
, <script>
, etc.
Below is an example of a custom head component that configures the global styles and fonts.
<!-- Load custom fonts -->
<link rel="preconnect" href="https://rsms.me/" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<!-- Apply global styles -->
<style is:global>
html {
font-family: 'Inter', sans-serif;
}
</style>
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
integrations: [
astrobook({
// Relative path to your custom head component
head: './src/components/CustomHead.astro',
}),
],
})
You can set the title for your website.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
export default defineConfig({
integrations: [
astrobook({
title: 'My Components Playground',
}),
],
})
You can enable Astrobook only on development by using the process.env.NODE_ENV
to conditionally include the astrobook
integration. This is useful when you
want to include Astrobook in your existing Astro project but don't want to build
it in production.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'
// https://astro.build/config
export default defineConfig({
integrations: [
// On development, Astrobook is available at http://localhost:4321/astrobook.
// On production, Astrobook is not included.
process.env.NODE_ENV === 'development'
? astrobook({ subpath: '/astrobook' })
: null,
],
})
If you're running Astrobook in an iframe, you can toggle the theme via a message.
const theme = 'light' // or "dark"
iframe.contentWindow.postMessage({ type: 'astrobook:set-theme', theme }, '*')
MIT