All docs
Core concepts2 min readUpdated

Test dark mode, themes, and viewports with modes

Capture a story in multiple viewports and themes with parameters.uiVerify.modes. Each mode gets its own baseline, and an existing Chromatic modes config carries over.

A mode is a capture variant of a story: a viewport and theme it should be screenshotted in. Declare modes on a story and UI Verify renders it once per mode, each diffed against its own per-mode baseline - so a single Button story can cover mobile light, desktop dark, and everything between, without a separate story for each.

Declare modes on a story

Set parameters.uiVerify.modes to an object keyed by mode name, each entry giving a viewport and/or a theme. UI Verify reads the same shape under parameters.chromatic, the drop-in Chromatic-compatible namespace, so an existing Chromatic config carries over unchanged. Set it on a single story, or on the component meta to cover the whole file.

Button.stories.tsx
export default {
  component: Button,
  parameters: {
    uiVerify: {
      modes: {
        "Mobile light": { viewport: "small", theme: "light" },
        "Desktop dark": { viewport: "large", theme: "dark" },
      },
    },
  },
};

A mode's viewport is a named viewport from your Storybook viewport options. For plain widths with no theme, the legacy viewports array still works - parameters.uiVerify.viewports: [320, 768, 1280] renders the story at each pixel width.

Each mode is its own baseline

A story rendered in three modes produces three screenshots, each with its own per-branch baseline, so accepting a dark-mode change never touches the light-mode baseline. Modes also multiply your snapshot count - three modes is three billable snapshots - so declare the ones that matter and lean on dense stories to keep the total down.

How is a theme applied?

A mode's theme value is set as the theme:<value> Storybook global for that capture, and light/dark also emulate the OS color scheme (prefers-color-scheme). Your Storybook has to respond to that global - usually through your existing theme decorator or addon - exactly as it does under Chromatic.

Do my Chromatic modes carry over?

Yes. UI Verify reads both parameters.uiVerify.modes and the Chromatic-compatible parameters.chromatic.modes (plus the legacy viewports width array), and uiVerify wins per key when a story sets both - so an existing Chromatic modes config renders the same variants with no change. A mode set to { disable: true } opts a story out of a mode it would otherwise inherit.

Modes multiply cost, so pair them with fewer, denser stories. Your coding agent can set them up with the Storybook determinism skill.

Visual testing for agents

UI Verify captures your UI on every pull request and an AI judge tells an intended change from a real regression. See how it works.

Get started