Skip to main content

Storybook 8 vs Ladle vs Histoire: Component Development 2026

·PkgPulse Team

TL;DR

Storybook 8 remains the standard for React component development — 30M+ downloads/week, mature ecosystem, test runner, Chromatic integration. Ladle is 10-50x faster to start (pure Vite, no custom webpack), making it compelling for large codebases where Storybook startup was painful. Histoire is Vite-native for Vue 3 — the Storybook equivalent for the Vue ecosystem. For most teams: Storybook 8 with Vite builder. For small/medium React projects prioritizing speed: Ladle.

Key Takeaways

  • Storybook 8: Vite-based by default (finally), 30M downloads/week, full ecosystem
  • Ladle: Pure Vite, no config needed, 10-50x faster startup, limited addon ecosystem
  • Histoire: Vue 3 focused, excellent Vite integration, Nuxt support
  • Speed: Ladle (1-2s start) vs Storybook 8 Vite (5-15s start) vs Storybook 8 Webpack (30s+)
  • Addons: Storybook has 1000+ addons; Ladle/Histoire have minimal ecosystems
  • Migration: Easy to migrate from Storybook to Ladle (same CSF format)

Downloads

PackageWeekly DownloadsTrend
@storybook/react~3M→ Stable
storybook~5M↑ Growing
@ladle/react~100K↑ Growing
histoire~30K↑ Growing (Vue)

Storybook 8: The Standard

npx storybook@latest init
# Storybook 8 uses Vite by default for React projects
// stories/Button.stories.tsx — Component Story Format (CSF3):
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from '../components/Button';
import { userEvent, within, expect } from '@storybook/test';

const meta: Meta<typeof Button> = {
  title: 'UI/Button',
  component: Button,
  tags: ['autodocs'],  // Auto-generate docs from props
  parameters: {
    layout: 'centered',  // Center in canvas
    backgrounds: {
      default: 'light',
    },
  },
  argTypes: {
    variant: {
      control: 'select',
      options: ['default', 'outline', 'destructive'],
    },
    size: {
      control: 'radio',
      options: ['sm', 'default', 'lg'],
    },
    onClick: { action: 'clicked' },
  },
};
export default meta;

type Story = StoryObj<typeof Button>;

export const Default: Story = {
  args: {
    children: 'Button',
    variant: 'default',
  },
};

export const AllVariants: Story = {
  render: () => (
    <div className="flex gap-2">
      <Button variant="default">Default</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="destructive">Delete</Button>
    </div>
  ),
};

// Interaction test (runs in test runner):
export const ClickInteraction: Story = {
  args: { children: 'Click Me', onClick: fn() },
  play: async ({ canvasElement, args }) => {
    const canvas = within(canvasElement);
    await userEvent.click(canvas.getByRole('button'));
    await expect(args.onClick).toHaveBeenCalled();
  },
};
# Storybook 8 commands:
npx storybook dev -p 6006        # Start dev server
npx storybook build               # Static build for deployment
npx test-storybook                # Run interaction tests
npx chromatic --project-token=... # Visual regression testing

Storybook 8 New Features

Storybook 8 improvements:
  → Vite as default bundler (was webpack — 3-10x faster)
  → @storybook/test replaces testing-library as built-in
  → Vitest integration for unit + component tests
  → Portable stories (use stories in Vitest)
  → Improved TypeScript types
  → Story decorators with TypeScript inference

Ladle: Vite-Native Speed

npm install -D @ladle/react
# Zero config! Works with any Vite project.
Ladle file structure — same as Storybook!
  → Uses CSF (Component Story Format)
  → Files: *.stories.tsx
  → Same Meta and StoryObj types
// Ladle uses the exact same story format as Storybook:
// button.stories.tsx — compatible with both!

import type { StoryDefault, Story } from '@ladle/react';

export default {
  title: 'UI/Button',
} satisfies StoryDefault;

export const Default: Story = () => <Button>Click me</Button>;

export const Variants: Story = () => (
  <div className="flex gap-2">
    <Button variant="default">Default</Button>
    <Button variant="outline">Outline</Button>
    <Button variant="destructive">Delete</Button>
  </div>
);
// package.json — add Ladle scripts:
{
  "scripts": {
    "ladle": "ladle serve",    // Dev server
    "ladle:build": "ladle build"  // Static export
  }
}

Ladle Speed Comparison

Project: 150 components, 450+ stories

Storybook 8 (Vite builder):
  Cold start: 12s
  Hot reload: 200ms

Ladle:
  Cold start: 1.8s  (6.7x faster)
  Hot reload: 80ms  (2.5x faster)

For a large enterprise codebase (500 components):
  Storybook 8 Vite: 30-45s cold start
  Ladle: 3-5s cold start
  Storybook 8 Webpack: 2-4 minutes cold start

Ladle Limitations

Ladle missing vs Storybook:
  ❌ No addon ecosystem (no a11y, viewport, backgrounds addon)
  ❌ No interaction tests (no play() functions)
  ❌ No Chromatic visual regression
  ❌ No test runner
  ❌ No MDX docs pages
  ❌ Less active development

Ladle use case:
  → Dev environment only (fast iteration)
  → Pair with Vitest/Playwright for testing
  → Teams who found Storybook too slow

Histoire: Vue 3 Native

npm install -D histoire @histoire/plugin-vue
# For Nuxt:
npm install -D histoire @histoire/plugin-nuxt
// histoire.config.ts:
import { defineConfig } from 'histoire';
import { HstVue } from '@histoire/plugin-vue';

export default defineConfig({
  plugins: [HstVue()],
  setupFile: './src/histoire.setup.ts',
  theme: {
    title: 'My Component Library',
    logo: { light: '/logo.svg', dark: '/logo-dark.svg' },
  },
});
<!-- Button.story.vue — Histoire story format: -->
<script setup lang="ts">
import { reactive } from 'vue';
import Button from './Button.vue';

const state = reactive({
  variant: 'default' as 'default' | 'outline' | 'destructive',
  label: 'Click me',
  disabled: false,
});
</script>

<template>
  <Story title="UI/Button">
    <Variant title="Default">
      <Button :variant="state.variant" :disabled="state.disabled">
        {{ state.label }}
      </Button>
    </Variant>
    
    <Variant title="All Variants">
      <div class="flex gap-2">
        <Button variant="default">Default</Button>
        <Button variant="outline">Outline</Button>
        <Button variant="destructive">Destructive</Button>
      </div>
    </Variant>
    
    <template #controls>
      <HstSelect v-model="state.variant" :options="['default','outline','destructive']"
        title="Variant" />
      <HstText v-model="state.label" title="Label" />
      <HstCheckbox v-model="state.disabled" title="Disabled" />
    </template>
  </Story>
</template>

Feature Comparison

Storybook 8LadleHistoire
FrameworkReact, Vue, Svelte, etc.React onlyVue 3 focused
Startup speedMedium (Vite)FastFast (Vite)
Addons✅ 1000+❌ Minimal❌ Limited
Interaction testsplay()
Chromatic
A11y checks✅ Addon
AutodocsPartial
Portable stories✅ (v8)
Vue support@storybook/vue3✅ Native

Decision Guide

Use Storybook 8 if:
  → Design system or component library (documentation matters)
  → Need interaction tests + Chromatic visual regression
  → Team already knows Storybook
  → Multiple frameworks in one project

Use Ladle if:
  → React only project
  → Storybook startup time is a pain point
  → Dev environment usage (no need for test runner)
  → Migrating from Storybook but want speed improvement

Use Histoire if:
  → Vue 3 or Nuxt project
  → Want Vite-native Vue component development
  → More visual control panel options than Storybook Vue

Compare Storybook, Ladle, and Histoire download trends on PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.