New to Claude Skills? Learn how to install them →

posthog on GitHub

Storybook Stories

Free

Create and manage Storybook stories for PostHog UI components.

Get this skill

Free · Opens the source repo

What Storybook Stories does

The Storybook Stories skill is designed for developers working with PostHog UI components, providing a structured way to write and manage Storybook stories. This skill simplifies the process of creating *.stories.tsx files that accompany your UI components, ensuring they are properly integrated into the PostHog environment. By following the conventions and guidelines outlined in the skill, developers can focus on building and testing their components effectively.

One of the key features of this skill is its awareness of the PostHog provider stack. All stories are automatically wrapped with necessary global decorators, which include essential providers like withAppProviders and a <Theme> component. This means developers do not need to worry about re-wrapping their stories, allowing them to concentrate on the visual aspects of their components. However, it is important to note that data-fetching components will render empty in Storybook due to the way the tRPC context is configured, which is a common pitfall that developers should be aware of.

To address the rendering challenges posed by data-fetching components, the skill encourages a separation of concerns by promoting the use of pure presentational components. This approach allows developers to create stories that focus solely on the visual representation of components, ensuring that they can be tested in isolation. By following the provided guidelines, developers can create effective visual stories that accurately represent the state of their components without the complications of data fetching.

This skill is particularly useful for developers who are actively contributing to the PostHog UI library or those who need to maintain existing components. It streamlines the process of writing Storybook stories, making it easier to visualize and test components in various states, ultimately leading to a more robust UI development workflow.

When to use it

Use this skill when adding or fixing `*.stories.tsx` files for PostHog UI components to ensure they are correctly set up and visualized in Storybook.

When not to use it

This skill may not be suitable for projects outside of the PostHog ecosystem or for components that do not follow the established conventions for Storybook integration.

What you can build with it

Creating New Stories

Use this skill when you need to add new `*.stories.tsx` files for PostHog UI components, ensuring they are properly set up.

Fixing Existing Stories

This skill is ideal for developers looking to maintain or fix existing Storybook stories within the PostHog UI library.

Visualizing Component States

Utilize this skill to create visual representations of different states of your UI components, aiding in testing and development.

How to install Storybook Stories

View source

1. Install with the skills CLI

npx skills add posthog/posthog/storybook-stories --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by posthog

Storybook stories in PostHog

Stories live next to components as *.stories.tsx and are collected by apps/code/.storybook/main.ts (its glob includes packages/ui/src/**/*.stories.tsx). Run/build:

pnpm --filter code storybook        # dev server on :6006
pnpm --filter code build-storybook  # static build (also a good CI/typecheck gate)

Every story is already wrapped (don't re-wrap)

apps/code/.storybook/preview.tsx applies two global decorators, so a story should not add its own providers or <Theme>:

  • withAppProviders — a QueryClient, the host tRPC context, a DI ServiceProvider, and a minimal TanStack Router. So useHostTRPC(), useService(), useRouterState(), etc. render instead of throwing "must be used within a Provider".
  • A <Theme> (Radix) bound to the dark/light toolbar global. This root provider is the one sanctioned Radix usage — it supplies the CSS tokens. Radix components are banned: build stories and components from @posthog/quill plus div + Tailwind (see UI Components).

Add a per-story decorator only to constrain layout (e.g. wrap in a maxWidth div so a full-width component sizes realistically).

The gotcha: data never arrives in Storybook

This is the thing that wastes time. In withAppProviders the tRPC ipcLink is a no-op (apps/code/.storybook/mocks/electron-trpc.ts), so:

  • Any query issued through useHostTRPC() (and hooks built on it, like useClaudeCliSessions) stays pending foreverquery.data is undefined, permanently.
  • useService(TOKEN) returns an inert proxy stub for anything not explicitly bound (service.foo().bar never throws, but calls are no-ops). Only a few tokens resolve for real: HOST_TRPC_CLIENT (a no-op client with a handful of stubbed methods), IMPERATIVE_QUERY_CLIENT, DIFF_WORKER_FACTORY.

So a component that fetches its own data renders its empty/loading branch in Storybook — frequently null. Storying it directly shows nothing.

The fix: split a pure presentational component

Separate the data/wiring from the rendering, and story the pure part — which also satisfies the repo rule "components render; hooks wrap exactly one query" (AGENTS.md). Keep both in the same file:

// Pure — takes data + handlers as props. This is what the story targets.
export function WidgetList({ items, onPick }: WidgetListProps) { … }

// Container — does the tRPC/useService wiring, renders <WidgetList/>.
export function Widget({ repoPath }: WidgetProps) {
  const { data } = useSomeQuery(repoPath);
  return <WidgetList items={data?.items ?? []} onPick={…} />;
}

Then each story is just args for WidgetList — one per visual state (empty, single, over-limit, in-flight/disabled, fallback text, …). Real example: packages/ui/src/features/task-detail/components/ContinueCliSessions.tsx + .stories.tsx.

Filtering/branching that lives in the container (not the pure view) isn't exercised by these visual stories — cover it with a small unit test if it's worth pinning.

Conventions

  • title groups in the sidebar, e.g. "Task Detail/ContinueCliSessions".
  • Build fixtures with a small factory (session(overrides)) rather than repeating object literals across stories.
  • Date.now()/new Date() are fine in stories, but fixed ISO strings keep relative-time output stable enough for visual review.
  • Typecheck covers stories (they're .tsx under the package); a build-storybook additionally catches Storybook-specific breakage.

Frequently asked questions about Storybook Stories

Similar skills