Skip to content
brix.v2 stable

Search documentation

70 guides

Documentation menu
Docs / Project tooling / StorybookRead Markdown ↗

Author and test Storybook stories

Initialize managed Preact Storybook, author colocated stories and interactions, and enforce accessible, translated, themed previews.

Managed Brix Storybook is Preact-only. Managed React applications and separately integrated external React hosts use their own React testing and catalog tooling.

Initialize a catalog

Preview, then initialize from the catalog owner:

brix storybook init --dry-run
brix storybook init
brix storybook dev

Initialization accepts a Brix application, library, or workspace root. It refuses to overwrite existing Storybook files, installs exact compatible packages, records the integration, adds scripts and TypeScript includes, and writes:

  • .storybook/main.ts
  • .storybook/preview.ts
  • .storybook/vitest.config.ts
  • .storybook/env.d.ts

Storybook itself uses React internally, so those exact React, ReactDOM, and type packages are development-only tooling dependencies. Your Brix application and stories continue to use Preact. Run brix doctor when configuration, dependencies, or scripts drift.

Write a colocated story

Place stories beside components as src/**/*.stories.tsx. Import supported story types, spies, interactions, assertions, and queries through brix/storybook/test:

import { expect, fn, type Meta, type StoryObj, userEvent, within } from "brix/storybook/test";
import { Button } from "./Button.tsx";

const meta: Meta<typeof Button> = {
  title: "Checkout/Button",
  component: Button,
  args: { label: "Continue", onClick: fn() },
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};

export const Clicked: Story = {
  play: async ({ canvasElement, args }) => {
    const canvas = within(canvasElement);
    await userEvent.click(canvas.getByRole("button", { name: "Continue" }));
    await expect(args.onClick).toHaveBeenCalledOnce();
  },
};

Use ordinary stories for stable visual states and play for user flows. Prefer role and accessible-name queries over CSS selectors. brix create ui-library supplies a component, colocated story, interaction, and library test as a starting point.

Enforce accessibility

The generated preview treats accessibility violations as test errors. This means brix storybook test checks the rendered story after its interaction alongside its assertions.

Keep the strict global policy. If a known component state requires an exception, make it explicit and reviewed at story level rather than downgrading all stories. An exception documents debt; it is not a replacement for semantic elements, labels, keyboard interaction, focus behavior, or contrast.

Preview translations

Compose static dictionaries into .storybook/preview.ts:

import { createBrixTranslationPreview, type Preview } from "brix/storybook/test";
import { dictionaries } from "../src/translations.storybook.ts";

const preview = {
  ...createBrixTranslationPreview({
    locales: ["sv", "en-GB"] as const,
    defaultLocale: "sv",
    dictionaries,
  }),
  parameters: { a11y: { test: "error" } },
} satisfies Preview;

export default preview;

Every listed locale needs a dictionary. The locale toolbar uses the same Preact provider semantics as islands, but Storybook does not run a server loader or require CMS credentials. Generate CMS snapshots in a separate explicit workflow and check in or supply stable preview data.

Apply the application theme

The generated integration discovers the application's Panda sources and includes managed styles. Author theme tokens and recipes through Brix and import generated utilities through #brix/panda/*; do not add a second Panda or PostCSS setup.

Keep global Storybook decorators and parameters in .storybook/preview.ts. Preserve the generated Brix wrapper while adding deliberate backgrounds, layout, or theme controls around it. See the styling guide.

Continue with own and operate storybook catalogs.