Ladle

repository·main·Indexed 23 days ago

https://github.com/tajo/ladle

An environment for developing, testing, and sharing React components. Ladle supports story-based development using Vite, MDX for documentation, and integration with Playwright for automated visual regression testing and snapshots. It provides tools for mocking network requests via MSW, managing component state with Story and Meta components, and a CLI for serving, building, and previewing component stories.

Tokens
25.8K
Snippets
105
Records
151
Agent score
83%

What's inside Ladle

  1. Introduction to Ladle

    main

    Ladle is a high-performance tool for developing and testing React components in an isolated environment. It is designed as a drop-in replacement for Storybook and supports the Component Story Format (CSF).

    Key features include:

    • Vite-powered: Uses Vite and esbuild for fast module serving and bundling.
    • Performance: Faster production builds, near-instant dev startup (with cache), and hot reloads under 100ms that preserve component state.
    • Automatic Code-splitting: Each story is code-split by default, keeping initial bundle sizes small regardless of the total number of stories.
    • Built-in Features: Supports controls, links, dark theme, RTL, preview mode, and React Fast Refresh.
    • Developer Experience: No configuration required, responsive (no iframes), and A11y/keyboard friendly.
    • Metadata Export: Automatically exports a meta.json file containing a list of stories and metadata for easier automated testing and crawling.
  2. Override background controls at the story level

    main

    You can override global background settings by defining argTypes directly on a specific story. This allows you to provide a different set of color options or a different name for the control for that specific story context.

    Note: Only one background control can be active at a time.

    export const Story = () => <div>Hello</div>;
    Story.argTypes = {
      background: {
        name: "Canvas background",
        control: { type: "background" },
        options: ["green", "yellow", "pink"],
        defaultValue: "pink",
      },
    };
  3. Setup Emotion

    main

    To use Emotion, install the required dependencies and configure the @vitejs/plugin-react-swc plugin in your vite.config.js to handle the JSX import source and SWC plugin.

    pnpm add @emotion/react @swc/plugin-emotion @vitejs/plugin-react-swc
    // vite.config.js
    import react from "@vitejs/plugin-react-swc";
    
    export default {
      plugins: [
        react({
          jsxImportSource: "@emotion/react",
          plugins: [["@swc/plugin-emotion", {}]],
        }),
      ],
    };
  4. Use the Test component

    main

    The Test component is a stateful React component that makes requests to the uOwn backend and manages the state of the tree.

    Before using the component, ensure the backend service is running by executing yarn add-service.

    import { Test } from "test/react";
    
    <Test
      onNodeChange={({ name, uuid }) => console.log(`Node selected ${name}`)}
      maxWidth="100%"
    />
  5. Set up visual snapshot testing with Playwright

    main

    You can automate visual snapshot testing for your React components by combining Ladle's meta.json export with Playwright. This workflow involves building Ladle, fetching the meta.json file to identify all stories, and dynamically generating Playwright tests that navigate to each story in preview mode, wait for the [data-storyloaded] selector, and compare a screenshot against a baseline.

    Prerequisites

    Install Playwright and sync-fetch:

    pnpm install @playwright/test
    pnpm install sync-fetch

    Implementation Steps

    1. Identify Stories: Ladle exports a meta.json file containing all stories and their parameters. Use this to drive your test generation.
    2. Configure Playwright: Set up a webServer in playwright.config.ts to automatically start your Ladle server before tests run.
    3. Generate Tests: Iterate over the stories in meta.json and create a test block for each. You can use custom metadata (e.g., meta.skip) to opt-out specific stories from snapshot testing.
    4. Run Tests: Use Playwright to capture screenshots and compare them to existing baselines.
    import { test, expect } from "@playwright/test";
    import fetch from "sync-fetch";
    
    const url = "http://127.0.0.1:61000";
    const stories = fetch(`${url}/meta.json`).json().stories;
    
    Object.keys(stories).forEach((storyKey) => {
      test(`${storyKey} - compare snapshots`, async ({ page }) => {
        test.skip(stories[storyKey].meta.skip, "meta.skip is true");
        await page.goto(`${url}/?story=${storyKey}&mode=preview`);
        await page.waitForSelector("[data-storyloaded]");
        await expect(page).toHaveScreenshot(`${storyKey}.png`);
      });
    });
  6. Configure global level controls

    main

    To apply args and argTypes to every story in your project, define them in .ladle/components.tsx.

    Control precedence (from highest to lowest):

    1. Per-story controls
    2. File-level controls
    3. Global level controls
    // .ladle/components.tsx
    export const args = {
      label: "Hello world",
    };
    
    export const argTypes = {
      cities: {
        options: ["Prague", "NYC"],
        control: { type: "check" },
      },
    };
  7. Configure visual snapshot tests using Ladle's meta.json

    main

    You can automate visual snapshot testing by creating a Playwright test file that dynamically generates tests for every story listed in Ladle's exported meta.json file.

    To implement this:

    1. Fetch the meta.json file from your running Ladle instance (e.g., http://localhost:61000/meta.json).
    2. Iterate through the stories object keys.
    3. For each story, navigate to the preview mode URL: /?story=${storyKey}&mode=preview.
    4. Wait for the [data-storyloaded] selector to ensure the story is loaded.
    5. Use Playwright's toHaveScreenshot assertion to compare the current state against a baseline.
    import { test, expect } from "@playwright/test";
    // we can't create tests asynchronously, thus using the sync-fetch lib
    import fetch from "sync-fetch";
    
    // URL where Ladle is served
    const url = "http://localhost:61000";
    
    // fetch Ladle's meta file
    // https://ladle.dev/docs/meta
    const stories = fetch(`${url}/meta.json`).json().stories;
    
    // iterate through stories
    Object.keys(stories).forEach((storyKey) => {
      // create a test for each story
      test(`${storyKey} - compare snapshots`, async ({ page }) => {
        // navigate to the story
        await page.goto(`${url}/?story=${storyKey}&mode=preview`);
        // stories are code-splitted, wait for them to be loaded
        await page.waitForSelector("[data-storyloaded]");
        // take a screenshot and compare it with the baseline
        await expect(page).toHaveScreenshot(`${storyKey}.png`);
      });
    });
  8. Customize story names and hierarchy

    main

    You can override default naming and hierarchy using storyName for individual stories or the title property in the default export for grouping.

    Rename a single story

    Assign a string literal to the .storyName property of the exported story.

    Customize hierarchy and levels

    Use the title property in the default export (of type StoryDefault) to define the navigation path. Use / to create sublevels.

    Note: All names (storyName, title, and meta) must be static string literals to support code-splitting.

    import type { StoryDefault, Story } from "@ladle/react";
    
    // Customizing hierarchy
    export default {
      title: "Level / Sub level",
    } satisfies StoryDefault;
    
    export const Button: Story = () => <button>My Button</button>;
    
    // Customizing individual story name
    Button.storyName = "Renamed Button";
  9. Upgrade to Ladle v3

    main

    Ladle v3 introduces several breaking changes and improvements. Key updates include:

    • Compiler: SWC is now the default, replacing Babel. This provides faster builds and startup. You can revert to Babel using @vite/plugin-react if necessary.
    • Node.js Support: Official support for Node v18 and v20. Node v16 is deprecated.
    • React Support: React 18+ is supported. React v17 is deprecated.
    • New Features: MDX stories, mocked dates, and improved CSS-in-JS support (Emotion, Styled-components, Tailwind, etc.).
    • API Changes: StoryDefault and Meta exported types are now interfaces to allow for easier extensions.
  10. Use built-in Ladle addons

    main

    Ladle does not currently support third-party addons, but it includes several built-in addons accessible via button icons in the bottom left corner of the interface. These include:

    • Accessibility (Axe)
    • Background
    • Controls (enabled only if args or argTypes are defined)
    • Dark theme
    • Links
    • MSW (for API mocking)
    • Preview mode
    • Right-to-left
    • Story source code
    • Width
  11. Customize the Story Source header

    main

    You can customize the header of the source addon by exporting a StorySourceHeader component from your .ladle/components.tsx file. The component receives a path prop representing the origin of the story, which you can use to provide custom information or hyperlinks (e.g., a GitHub link).

    import type { SourceHeader } from "@ladle/react";
    
    export const StorySourceHeader: SourceHeader = ({ path }) => {
      return (
        <b>
          Github link? <code className="ladle-code">{path}</code>
        </b>
      );
    };