In Storybook, what is a story, and why does the number of stories you write for a component decide what an automated visual regression suite can catch?
answer
- one export, one fixed state
- the tool screenshots what exists
- story list is the test matrix
- unwritten states get no baseline
- silence is not the same as green
basics
~10 sA Storybook story is a named export that renders one component in one fixed state. Visual regression tools screenshot stories, so any state without a story has no baseline and its regressions ship unnoticed.
solid answer
~50 sA story is a single named example of a component in one specific state. In Component Story Format 3 — the default since Storybook 7 — you write a default export naming the component, then one named export per state, each supplying its own `args`. A visual regression tool walks that story list, renders each story in isolation and screenshots it, so the story catalogue *is* the visual test matrix. Coverage becomes a writing decision rather than a tool setting: if `Loading`, `Empty` and `Error` have no stories, nothing is compared for them and a regression in those states passes silently. The habit that follows is to add a story for every visually distinct state the component can reach, including the awkward ones — long text, no data, failure — not just the happy path used in the docs.
code
typescript · 22 linesimport type { Meta, StoryObj } from '@storybook/react';
import { Alert } from './Alert';
const meta: Meta<typeof Alert> = { component: Alert };
export default meta;
type Story = StoryObj<typeof Alert>;
export const Info: Story = {
args: { tone: 'info', message: 'Changes saved.' },
};
export const Failure: Story = {
args: { tone: 'error', message: 'Could not save changes.' },
};
export const LongMessage: Story = {
args: {
tone: 'info',
message: 'Changes saved to the shared workspace and shared with everyone on the team.',
},
};go deeper
Be able to say plainly what a story is — a named export rendering one component in one fixed state — and that a visual tool screenshots each story it finds.
Explain that story coverage, not tool configuration, defines the visual matrix, and name which states earn their own story: variants, lifecycle states and realistic content boundaries.
Show how you keep the catalogue from drifting behind the component, and how you decide that a missing story, not the diff tool, is the reason a regression escaped.
Own the convention: what states a component must ship with, how that is enforced in review rather than policed per pull request, and what the growing catalogue costs the team.
## What a story actually is A story is a named export in a `*.stories.*` file that renders one component in one specific state. In Component Story Format 3, the default since Storybook 7, the file has a default export — the *meta* — naming the component and any shared configuration, then one named export per state. Each named export is an object whose `args` supply that state's props. ```ts const meta = { component: Alert }; export default meta; export const Info = { args: { tone: 'info', message: 'Saved.' } }; export const Failure = { args: { tone: 'error', message: 'Could not save.' } }; ``` Two things follow from that shape. First, a story is *addressable*: the browser can be pointed at exactly this component in exactly this state, with nothing else on the page. Second, a story *asserts nothing on its own*. It is a render target. Something else — a test runner, a cloud snapshot service — turns it into a check by rendering it and doing something with the result. ## Why the story list becomes the visual matrix Visual regression tooling for Storybook works by enumeration: it discovers the stories, renders each one, captures an image, and compares that image against a stored baseline for the same story. There is no analysis of the component's source, no exploration of prop combinations, no inference from types. If a state is not expressed as a story, the tool never renders it, never captures it, and never compares it. That gives the model its main strength and its main trap. The strength is that you get visual coverage as a by-product of documenting the component — the stories you write for humans double as render targets for machines. The trap is that the suite reports green for states it never looked at. Absence of a story does not produce a failure; it produces silence, which reads exactly like success. ## Which states earn their own story A useful rule is: a state deserves a story when it is *visually distinct* and *reachable in production*. In practice that means: - **Variants that change appearance** — tone, size, emphasis, density. - **Lifecycle states** — loading, empty, partially loaded, error. - **Interaction-adjacent states expressible as props** — disabled, selected, invalid. - **Content boundaries** — the longest realistic label, a two-character label, an unusually large number, a long word with no break opportunity. That last group is the one teams most often skip and most often regret. A card story with the title `"Hello"` proves the card renders; it proves nothing about what happens when a real title runs to ninety characters. Overflow, truncation and wrapping bugs live exactly there, and a story with idealised content gives them a green baseline to hide behind. ## What a story is deliberately not A story is not an assertion, so "we have stories" is not the same as "we have tests". A story is also not proof that the component looks right *in the product* — it renders alone, with whatever globals the Storybook preview provides, and real pages supply neither. Both of those are separate concerns; the point here is only that the story is the unit the visual suite iterates over. ## Keeping the catalogue honest Story catalogues drift. A component gains a `compact` variant in a sprint, the variant ships, and no story is added; six months later the visual suite still covers the component's original three states. Teams that keep this under control usually do two things. They make the expected story set part of a component's definition of done — new visual state means new story, in the same change — and they backfill a story whenever a visual bug reaches production, so the escape becomes permanent coverage. Neither is a tool feature; both are review habits. ## The cost side Stories are not free. Each one is another render, another image, and another thing a human may have to look at when it changes. That is a reason to choose states deliberately rather than to permute every prop, but it is not a reason to ship a single default story and call the component covered — the whole value of the approach is that the states you care about have a pinned appearance.
- Why is a story on its own not a test?A story only declares a render target — it says "put this component in this state" and stops. It becomes a check when something else acts on it: a visual service that screenshots it and compares the image, or a runner that renders it and asserts. That separation is why the same story can serve documentation and testing at once.
- How do you stop the story set drifting behind the component's real states?Tie it to the change, not to a cleanup pass: a new visual variant ships with its story in the same pull request, and reviewers check for that the way they check for tests. Then backfill — every visual bug that reaches production earns a story for the state it escaped through, so the catalogue grows from real misses.
The visual tool is a photographer who only shoots the poses you arrange. Poses nobody set up are not photographed badly — they are not photographed at all.
saying these in an interview costs you the question
- Thinks one default story per component is enough visual coverage.
- Assumes the tool discovers component states without stories being written.
- Writes only happy-path stories and skips loading, empty and error states.
- Uses idealised short content, so overflow bugs never get a baseline.
- Reads a green run as coverage of states that have no story at all.