{"post":{"slug":"how-to-set-up-storybook-2026","title":"How to set up Storybook in 2026","excerpt":"Storybook 8 is faster, Vite-native, and ships a built-in test runner. This guide covers installation, story writing, interaction testing, and plugging Storybook into CI.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">S</span>torybook went from a nice-to-have demo tool to a core part of the component development workflow between 2023 and 2026. Version 8 switched to Vite as the default builder, added a built-in test runner powered by Playwright, and tightened the TypeScript story format. If you write UI components, this is the setup that pays for itself in the first PR review cycle.\n\n## What changed in 2026\n\n- **Storybook 8** ships with the Vite builder by default — no Webpack unless you opt in. Cold starts went from 20–30 s to under 3 s on a typical project.\n- **`@storybook/test`** unified `@storybook/jest` and `@storybook/testing-library` into one package matching Vitest/Playwright conventions.\n- **`Component Story Format 3` (CSF3)** is the only format you need — object-style, TypeScript-native, no more default export decorators mess.\n- **Autodocs** generates a full API table from your TypeScript props automatically — no manual MDX doc page required.\n- **`storybook dev --test`** runs stories + interaction tests in headless mode for CI with one command.\n\n## Install\n\n```bash\nnpx storybook@latest init\n# Detects your framework (React, Vue, Svelte, etc.) and configures automatically\n```\n\nFor an existing Vite project it will add `.storybook/main.ts`, `.storybook/preview.ts`, and example stories.\n\n## Configure `.storybook/main.ts`\n\n```ts\nimport type { StorybookConfig } from '@storybook/react-vite'\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.stories.@(ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n    '@storybook/addon-a11y',\n    '@storybook/addon-interactions',\n  ],\n  framework: { name: '@storybook/react-vite', options: {} },\n  docs: { autodocs: 'tag' },\n}\n\nexport default config\n```\n\n## Write a story\n\n```tsx\n// src/components/Button/Button.stories.tsx\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { Button } from './Button'\n\nconst meta: Meta<typeof Button> = {\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    variant: { control: 'select', options: ['primary', 'secondary', 'ghost'] },\n  },\n}\n\nexport default meta\ntype Story = StoryObj<typeof Button>\n\nexport const Primary: Story = {\n  args: { variant: 'primary', children: 'Save changes' },\n}\n\nexport const Loading: Story = {\n  args: { variant: 'primary', loading: true, children: 'Saving…' },\n}\n```\n\n## Add interaction tests\n\n```tsx\n// src/components/LoginForm/LoginForm.stories.tsx\nimport { within, userEvent, expect } from '@storybook/test'\n\nexport const FilledAndSubmitted: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement)\n    await userEvent.type(canvas.getByLabelText(/email/i), 'user@example.com')\n    await userEvent.type(canvas.getByLabelText(/password/i), 'secret')\n    await userEvent.click(canvas.getByRole('button', { name: /sign in/i }))\n    await expect(canvas.getByText(/welcome/i)).toBeInTheDocument()\n  },\n}\n```\n\nRun interaction tests in CI:\n\n```bash\nnpx storybook dev --ci --test\n# or\nnpx storybook build && npx storybook test --url http://localhost:6006\n```\n\n## Story patterns table\n\n| Pattern | When to use |\n| --- | --- |\n| Default / empty state | Every component |\n| Loading / skeleton state | Async components |\n| Error / invalid state | Forms, data fetchers |\n| All variants in one story | Design reference |\n| Interaction (play fn) | Interactive components |\n| A11y violation check | Public-facing UI |\n\n## Storybook vs alternative approaches\n\n| Approach | Good for | Weakness |\n| --- | --- | --- |\n| Storybook 8 | UI components, design review | Adds dev dependency |\n| Vitest + RTL | Logic-heavy components | No visual preview |\n| Playwright component | Real browser tests | Slower feedback loop |\n| Manual dev page | One-off debugging | Doesn't scale |\n\n## How to pick what to story\n\n1. **Every shared component in a design system** — stories become the living spec.\n2. **Components with multiple variants** — props tables from autodocs replace Figma spec sheets.\n3. **Components with complex interaction** — write a `play` function instead of a separate e2e test.\n4. **Skip:** leaf utilities, hooks, and helper functions — test those in Vitest, not Storybook.\n\n## Common mistakes\n\n**Storing mocked data only in stories** — if your mock data is useful elsewhere, put it in a shared `__fixtures__` file and import into the story.\n\n**Forgetting to tag `autodocs`** — without `tags: ['autodocs']` in the meta, the auto-generated docs page isn't built.\n\n**Using the Webpack builder** — unless you have a legacy project with Webpack-only plugins, there's no reason not to use the Vite builder in 2026.\n\n**Not running stories in CI** — Storybook's value drops if nobody catches broken stories before merge. Add `storybook test` to your pipeline.\n\n## What to skip\n\n- **MDX docs pages** for every component — autodocs does 80% of the job; write MDX only for complex usage guides.\n- **`storybook-addon-designs` Figma embeds** — useful for design handoff but adds overhead; evaluate whether your team actually reads them.\n- **Multiple frameworks in one Storybook** — it's possible but painful; keep one Storybook per framework package.\n\n## FAQ\n\n**Can I use Storybook without React?**\nYes. Storybook 8 supports Vue 3, Svelte 5, Angular 17+, Web Components, and more. The setup command auto-detects the framework.\n\n**Does Storybook replace e2e tests?**\nNo — interaction tests in Storybook run in a browser-like iframe context, not a real user session. Use them for component-level flows; use Playwright for full user journeys.\n\n**How do I handle global providers (theme, auth)?**\nWrap in `.storybook/preview.ts` via `decorators`. Any provider you add there applies to every story.\n\n**How expensive is Chromatic?**\nChromatic's free tier covers ~5,000 snapshots/month, which is enough for a small project. Paid plans start at ~$149/month for larger teams.\n\n## Where to go next\n\n- [How to set up Vitest in 2026](/blog/how-to-set-up-vitest-2026)\n- [How to write e2e tests in 2026](/blog/how-to-write-e2e-tests-2026)\n- [How to configure Vite in 2026](/blog/how-to-configure-vite-2026)","hue":317,"metaTitle":"How to Set Up Storybook in 2026 (Vite + Testing)","metaDescription":"Complete 2026 Storybook setup guide. Install Storybook 8 with Vite, write stories, add interaction tests, and run in CI with coverage.","keywords":["how to set up storybook 2026","storybook 8 tutorial","storybook vite setup 2026","storybook react 2026","storybook interaction testing","component driven development 2026","storybook ci pipeline","chromatic visual testing 2026","storybook typescript configuration","storybook test runner 2026"],"tldr":["**Storybook 8 uses Vite by default** — startup is near-instant compared to the old Webpack builder.","**Stories are the source of truth** for component state — design, development, and testing all read from the same file.","**`@storybook/test`** lets you write Playwright-style interaction tests inside stories, run via the CLI test runner.","**Chromatic** (the cloud service) adds visual regression testing on top of Storybook with zero config.","**Skip:** writing stories for every internal utility component — focus on UI components that designers and reviewers actually need to inspect."],"readTime":"4 min read","wordCount":891},"related":[{"slug":"how-to-set-up-vitest-2026","title":"How to set up Vitest in 2026","excerpt":"Vitest is the default unit-test runner for Vite-based projects in 2026 — fast, zero-config, and Jest-compatible. This guide wires it up from scratch to CI-ready in minutes.","category":"code","date":"February 27, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":315},{"slug":"how-to-write-e2e-tests-2026","title":"How to write e2e tests in 2026","excerpt":"End-to-end tests catch what unit tests miss — broken flows, real browser quirks, and integration failures. This guide covers Playwright setup, writing reliable tests, and running them in CI.","category":"code","date":"March 18, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":316},{"slug":"what-is-test-driven-development-2026","title":"What Is Test-Driven Development in 2026?","excerpt":"Test-driven development means writing a failing test before the code that makes it pass, then refactoring with that test as a safety net. Here is the red-green-refactor cycle explained for 2026.","category":"code","date":"July 24, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":240}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-set-up-ssl-2026","title":"How to set up SSL in 2026: TLS, certificates, and HTTPS done right","excerpt":"HTTPS is non-negotiable in 2026 — browsers flag plain HTTP, and search engines penalize it. Here is how to get certificates, configure TLS, and stay secure.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":309},"older":{"slug":"how-to-set-up-stripe-payments-2026","title":"How to set up Stripe payments in 2026","excerpt":"Stripe is still the default payment processor for web apps in 2026. This guide covers the modern integration path — Checkout, Payment Element, webhooks, and going live safely.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":321}}