> [Agent navigation index](/llms.txt)

# 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:

```sh
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`:

```tsx
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`:

```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](/docs/styling).

Continue with [own and operate storybook catalogs](/docs/storybook-catalogs).
