storybookjs/storybook
github.com/storybookjs/storybook ↗ · 3999 files · 19.6 MB · scan capped
Build bulletproof UI components faster Storybook is a frontend workshop for building UI components and pages in isolation.
Overview
Storybook is a frontend workshop for developing, documenting, and testing components and pages in isolation. This TypeScript monorepo publishes a core runtime, framework integrations, builders, renderers, and addons; its Node server coordinates a manager UI and a separate preview iframe. At commit dc9b30e8fd8a71383ec01b9510f38bee51457e8a, it also exposes registered agent toolsets through CLI, SDK, and MCP interfaces, including documentation lookup, story previews, reviews, and tests.
System map
The product separates Node configuration and build orchestration from browser navigation and component execution. Framework presets select builders and renderers, while the published core package supplies shared APIs and runtime infrastructure. State spans browser storage, runtime service state, generated static artifacts, and a local instance registry. Contributor tooling and agent evaluation form separate workspace concerns.
- The Yarn workspace includes agent-eval, code/core, addons, builders, frameworks, renderers, libraries, presets, and scripts; the root pins yarn@4.18.0.
- dispatcher.ts imports the bundled core binary for dev/build/index/ai/tools/skills, routes init to create-storybook, and routes other commands to @storybook/cli.
- Core separates server orchestration, manager UI/API, preview rendering/API, channels, AST tooling, and testing support; its package exports distinguish source resolution from published dist modules.
- The React-Vite framework selects @storybook/builder-vite and @storybook/react/preset; builder-vite serves transformed iframe.html and installs Vite middleware.
- storybookDevServer creates a Polka application, installs Host/access/cache middleware, registers index.json, and starts manager and preview builders on the same HTTP server.
- Static builds emit manager and preview assets, index.json, optional project.json, service snapshots, and feature-gated manifests into the selected output directory.
- Storage boundaries include manager local/session storage, JSON service snapshots under outputDir/services, and runtime instance records under the user's .storybook/instances directory.
- NX compiles dependency packages before consumers and defines cached checks; agent-eval separately exposes experiment, comparison, analysis, and Next.js playground build commands.
Feature catalog
The inspected feature surface covers story navigation, live component manipulation, documentation, accessibility, automated testing, and static publication. CLI commands provide development, builds, indexing, and agent access. Addons extend the workshop with panels and runtime hooks. This is a bounded catalog of evidenced capabilities, not an exhaustive enumeration of every screen or integration.
- The dev command supports host/port selection, HTTPS certificate paths, CI mode, smoke testing, exact-port enforcement, initial paths, docs mode, and preview-only operation.
- The build command supports configurable output, documentation-only and test builds, preview-only output, and statistics; index writes a standalone JSON story index.
- selectStory navigates to story or docs routes, supports referenced Storybooks and scroll anchors, and resolves group/component selections to a filtered descendant.
- Controls offers Update story, Create new story, and Reset; updates send changed args, while creation sends current args and a new export name.
- Documentation supports MDX3 compilation and distinct MDX/CSF docs renderers; addon-docs resolves React, React DOM, and MDX aliases for the consuming project.
- The accessibility addon supplies vision simulation and afterEach checks, skips ghost/manual/disabled/off cases, and classifies violations as warnings for todo or failures for error mode.
- Addon-vitest exposes a test toolset without requiring an already-running server; its live server extras require a Vite builder and support story-index refresh and watch toggling.
- Agent access includes auto/required/local tools modes, core docs/stories/review toolsets, MCP capability registration, and skills Markdown for stories, write-story, and setup.
Data flow
Configuration enters through CLI options and project presets, then supplies story discovery, builders, and runtime feature gates. The server produces an index whose import paths connect static discovery to executable preview modules. Channel events carry selections, args, and results between realms. Persistence is explicit: browser preferences, rewritten story files, static snapshots, and instance discovery records have different owners.
- dev() combines CLI input with a default ./.storybook config directory, development mode, cache, and package metadata before withTelemetry invokes buildDevStandalone().
- Story specifiers are normalized once and shared by reference; watched story changes invalidate individual index entries, while preview configuration changes invalidate the complete index.
- extractStories converts an absolute source path to an importPath, derives titles from the matching specifier, and delegates extraction to the first matching indexer's createIndex().
- StoryStore resolves storyId through the index, calls importFn(importPath), processes the CSF exports, combines story/component/project annotations, and initializes args and hook state.
- Manager updateStoryArgs emits UPDATE_STORY_ARGS with a ref target; Preview.onUpdateArgs updates the args store, rerenders or remounts matching renders, and emits STORY_ARGS_UPDATED.
- Controls serializes changed args with csfId/importPath; initializeSaveStory parses them, mutates the selected CSF export or duplicate, formats printed source, and writes the file.
- Manager Store.setState first awaits React's state update, then persists the delta through a URL handler, session storage, or local storage; initial state gives session values precedence over local values.
- Static service queries require load/staticPath/staticInputs, validate each input, execute against fresh runtimes, merge snapshots by logical path, and serialize JSON into outputDir/services.
Behavior traces
Three concrete flows were followed through implementation: development startup, selecting and rendering a story, and saving Controls changes to source. Startup has separate configuration-discovery and final preset passes. Selection branches between stories and docs and handles asynchronous replacement of an existing render. Saving crosses from browser events to AST mutation and filesystem output, then returns through correlated response events.
- Startup begins dispatcher.run() → core dev action → resolveDevCommandOptions() → dev() → withTelemetry() → buildDevStandalone(); invalid CLI options use handleCommandFailure().
- buildDevStandalone resolves port/config → first loadAllPresets → builder selection → second loadAllPresets → features/services/server-channel hooks → storybookDevServer; the server starts builders, listens, and conditionally opens the browser.
- Initial preview selection runs initializeWithStoryIndex() → selectSpecifiedStory() → entryFromSpecifier() → setSelection() → STORY_SPECIFIED/CURRENT_STORY_WAS_SET → renderSelection(); missing selection or index matches produce explicit error views.
- renderSelection resolves the entry → constructs StoryRender/MdxDocsRender/CsfDocsRender → prepare(); StoryRender.prepare calls StoryStore.loadStory → loadCSFFileByStoryId → importFn → storyFromCSFFile.
- After preparation, the preview emits STORY_PREPARED and renders to an element; StoryRender applies loaders → beforeEach → mount → conditional play, while React renderToCanvas creates the story subtree and calls renderElement inside act.
- Update story runs SaveStory.onSaveStory → Controls saveStory → experimental_requestResponse(SAVE_STORY_REQUEST); the dev preset has already registered initializeSaveStory, which reads/parses CSF, checks source/export names, and updates args or duplicates the export.
- The save handler formats source → concurrently writes and waits for STORY_RENDERED or 3000 ms → emits SAVE_STORY_RESPONSE; the manager resets args and optionally selects the new story, while errors produce a failed response and notification.
- Static build runs output cleanup → configuration/preset resolution → services registration → optional manager build → service snapshots before dependent manifests → preview build alongside remaining output effects.
Testing signals
Tests and CI definitions were inspected, not executed; no passing result or measured coverage is asserted. Vitest combines package projects with a separate browser-backed Storybook UI project. Inspected tests exercise rendering contracts, source mutation, token validation, and CLI attachment. Explicit exclusions and mocked boundaries limit what those tests demonstrate, and the inventory is bounded rather than exhaustive.
- The root Vitest configuration includes agent-eval and package projects, uses threads and Istanbul coverage, and excludes story files from coverage; the Storybook browser project is omitted on Windows CI.
- The core Vitest project enables type checking, Node resolution for oxc modules, a Polka URL alias, and separate benchmark file inclusion.
- storybook-ui uses addon-vitest, includes the vitest tag, runs headless Chromium through Playwright, and loads the internal Storybook setup file.
- Browser story tests explicitly exclude Zoom, docs blocks, benchmarks, and UseState names; SaveStory's Created play asserts a mocked createStory callback, but its meta carries !vitest.
- StoryRender unit tests use mock renderers/stores and assert autoplay true/false behavior; those assertions exercise lifecycle decisions rather than a real browser/framework rendering integration.
- CSF arg-mutation tests load fixture files, parse their ASTs, apply updateArgsInCsfFile, and assert unsupported forms reject; token tests cover missing, empty, unequal-length, special-character, and Unicode inputs.
- tools-attach Playwright tests launch the compiled CLI and check required attach, auto attach, local interception, and silent no-instance fallback; live attachment cases skip against static builds.
- Fork CI defines Linux/Windows unit jobs and installs Chromium, while NX CI has only workflow_dispatch enabled and retains a job condition for PR/push/schedule events; these definitions were inspected without running them.
Risk map
The principal sensitive boundaries are dev-server access, source-file rewriting, output-directory deletion, package execution, and instance-token persistence. The source contains safeguards, including token comparison, Host checks, and owner-only registry permissions. Findings below are source observations or explicitly labeled hypotheses, not confirmed vulnerabilities. Partial inspection cannot establish whole-repository test gaps or the absence of additional protections.
- WebSocket upgrades validate a supplied Origin and token unless skipValidation is set; non-browser clients may omit Origin, and buildDevStandalone sets skipValidation for WebContainer environments.
- Host validation permits all hosts when allowedHosts is true or host is 0.0.0.0 with an empty allowlist; startup warns about the latter configuration.
- Hypothesis requiring wider validation: SAVE_STORY_REQUEST accepts importPath and joins it to process.cwd() before reading and writing; the inspected handler does not bind that path to an indexed entry or check containment, making the upstream channel trust boundary consequential. (inferred)
- buildStaticStandalone recursively removes the resolved outputDir before loading configuration; its visible guards reject empty input and '/', so output-path handling has a filesystem-wide potential blast radius.
- Instance discovery persists the WebSocket token outside the project under .storybook/instances; records are written through a restricted temporary file and rename, with chmod and Windows icacls enforcement.
- External CLI dispatch can execute an installed package binary or download/run a versioned package through the detected package manager, making command routing a process and package-supply boundary.
- Tools attachment depends on import order: STORYBOOK_ATTACHED_TOOLS must be set before loading runtime machinery so UniversalStore becomes a follower; cross-installation attachment spawns the recorded installation rather than mixing module copies.
- Accessibility results are not universally fatal: default addon parameters use todo, checks skip several configured cases, and caught errors are rethrown only for standalone Vitest runs.
Extension points
Storybook exposes extension seams at configuration presets, builders, renderers, manager addons, story indexers, and schema-driven services. Agent transports share registered toolsets instead of independently implementing operations. Registration and initialization conditions are part of those contracts. New integrations should preserve runtime ownership and use the existing hooks appropriate to their boundary.
- Framework presets connect a builder and renderer through core and can alter bundler configuration through viteFinal; React-Vite uses this hook for conditional docgen plugins.
- Builders provide start/build/bail and optional changeDetectionAdapter implementations; builder-vite supplies live and headless change-detection adapters depending on server/options availability.
- Renderer renderToCanvas receives RenderContext and a canvas element and returns cleanup; the React implementation supplies framework-specific mounting, error boundaries, and remount behavior.
- Server extensions can use options.extendServer, project middleware, and experimental_devServer preset hooks; those hooks run before preview builder startup.
- Custom story indexers provide a test matcher and createIndex(file, { makeTitle }); extractStories fails explicitly when no indexer matches.
- Manager addons register loader callbacks and add typed elements through AddonStore; Controls demonstrates a feature-gated PANEL registration with a rendered ControlsPanel.
- defineService supports initial state, queries, and commands with schema validation; server registration is a relay hub, and load-enabled queries can provide staticInputs/staticPath for snapshot generation.
- Toolsets define schemas and one handler returning data/Markdown outcomes; registerToolset uses a realm-global map and rejects duplicate IDs or derived transport-name collisions, while addon-vitest registers its toolset and responder together.
Contributor handoff
Use this report as a source map for the pinned commit, then recheck checkout-specific instructions and implementation before editing. Tests and CI were inspected, not executed; verification commands below are guidance for subsequently authorized implementation work. Investigation covered more than twelve implementation files and three concrete flows, but remains bounded rather than exhaustive. Keep edits within the owning package and preserve contracts across server, manager, preview, and agent transports.
- AGENTS.md is canonical and CLAUDE.md is a reference; start core/preset/service/tools work with the architecture guide and read the linked testing/sandbox/task guides when relevant.
- The contributor environment pins Node 22.22.3 and Yarn 4.18.0 with node-modules linking; prefer existing NX compile/check targets and non-production configurations during routine iteration.
- For later authorized validation, use focused yarn test patterns for utilities and stories with play functions for React behavior; tools attachment E2E requires the running internal UI from the same checkout.
- After authorized edits, repository guidance requires oxfmt formatting from code/, targeted oxlint checks, explicit relative module extensions, and Storybook server/client loggers.
- Before changing agent operations, read the open-service and tools contracts; keep services/toolsets under the same gate, and preserve the distinction between thrown execution failures and returned ok:false outcomes.
- Avoid broad assumptions about CSF mutation: the preferred shared API exposes changed/mutationDiagnostics, while the Controls save implementation explicitly rejects arrow/call CSF2 forms except recognized CSF4 story calls.
- Do not default to yarn start or untemplated yarn task dev; generated sandboxes belong beside the checkout, and accidental generated manager export changes should be excluded from unrelated diffs.
- PRs target next and require Area: Summary plus Manual testing metadata; Danger evaluates trusted base-branch code, and the manually triggered NX workflow should not be mistaken for evidence of automated checks passing.
Languages
| Language | Files | Share of source |
|---|---|---|
| TypeScript | 4796 | 89% |
| Markdown | 1183 | docs/config |
| JSON | 596 | docs/config |
| JavaScript | 346 | 6% |
| Vue | 119 | 2% |
| Svelte | 111 | 2% |
| CSS | 59 | docs/config |
| YAML | 54 | docs/config |
Start reading here
Probable source entrypoint: code/ — inferred from the directory tree and manifest, not the upstream docs.
Source roots
code/ (2064 files) agent-eval/ (438 files) CONTRIBUTING/ (1 files)
Source layout — agent-eval/
| Path | Files |
|---|---|
agent-eval/app/ | 10 |
agent-eval/baselines/ | 19 |
agent-eval/evals/ | 103 |
agent-eval/.env.example | 1 |
agent-eval/.gitignore | 1 |
agent-eval/README.md | 1 |
agent-eval/eval-matchers.d.ts | 1 |
agent-eval/eval.d.ts | 1 |
Repository structure
| Top-level path | Files |
|---|---|
code/ | 2064 |
docs/ | 865 |
agent-eval/ | 438 |
test-storybooks/ | 293 |
scripts/ | 202 |
.github/ | 43 |
.agents/ | 28 |
.claude/ | 14 |
Docs found: AGENTS.mdCLAUDE.mdCONTRIBUTING.mdREADME.mddocs/_snippets/actions-filtering-example.mddocs/_snippets/actions-spyon-basic-example.mddocs/_snippets/addon-a11y-add.mddocs/_snippets/addon-a11y-config-context-in-story.mddocs/_snippets/addon-a11y-config-in-meta-and-story.mddocs/_snippets/addon-a11y-config-in-preview.md
Package
package.json — @storybook/root, 13 declared dependencies.
@nx/workspace@playwright/test@types/kill-porthttp-serverhuskyjitikill-portlint-stagednxoxfmtstd-envvite
CI & config entrypoints
README.md— Repository readmeAGENTS.md— Agent instructionsCLAUDE.md— Claude instructions.github/workflows/agent-eval.yml— GitHub Actions workflow.github/workflows/agent-scan.yml— GitHub Actions workflow.github/workflows/agentic-ref-eval.yml— GitHub Actions workflow.github/workflows/claude-code-review.yml— GitHub Actions workflow.github/workflows/claude.yml— GitHub Actions workflow.github/workflows/copilot-setup-steps.yml— GitHub Actions workflow.github/workflows/danger-js.yml— GitHub Actions workflow
Structural health signals
Average score 8.3/10 across 96 analyzed source files; 2 hotspots surfaced.
scripts/eval/collect-pr-data.ts— 1589 lines, score 5.9 (Large file, Deep nesting)code/addons/vitest/src/node/vitest-manager.ts— 606 lines, score 6.4 (Large file, Deep nesting)code/core/src/manager-api/modules/stories.ts— 1410 lines, score 6.6 (Large file, Deep nesting)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
dc9b30e8fd8a2026-10-02 — Merge pull request #36560 from storybookjs/claude/relaxed-bohr-ezqvks0393cea9a56b2026-10-02 — Merge pull request #36549 from storybookjs/fix/cli-quiet-per-project-noticese110f2ab89412026-10-02 — Merge pull request #36431 from storybookjs/kasper/sb-2078-install-skills-init-upgradeb8d7a1350ef02026-10-02 — ci: run agent-eval unit tests only on CircleCI Linux133975f763392026-10-02 — fix(cli): keep Vercel's telemetry on for prerelease skills installs