Storybook
Storybook CSF and configuration rules from eslint-plugin-storybook.
They check Component Story Format conventions (default export meta, named story exports, play-function shape) and configuration pitfalls in .storybook/main.ts.
Source: eslint-plugin-storybook (MIT).
Rule index
Each rule name links to the detailed section below.
Examples come from the checked lint corpus or package-level rule tests when project layout matters.
storybook/await-interactions: Requireawaiton Storybook interaction helpers inside aplayfunction.storybook/context-in-play-function: Require forwarding the play-functioncontextargument.storybook/csf-component: Require the CSF default meta object to declare acomponent.storybook/default-exports: Require every story file to provide the CSF default export.storybook/hierarchy-separator: Reject the legacy|separator in Storybook story titles.storybook/meta-inline-properties: Requiretitleandargsin CSF meta.storybook/meta-satisfies-type: Require CSF meta objects to type-check withsatisfies Meta<...>rather than.storybook/no-redundant-story-name: Rejectnamemetadata on a story when it matches Storybook’s auto-derived name from the export identifier.storybook/no-renderer-packages: Reject direct imports from Storybook renderer packages.storybook/no-stories-of: Reject the legacystoriesOf(...)builder API.storybook/no-title-property-in-meta: Reject thetitleproperty in CSF meta.storybook/no-uninstalled-addons: Validate Storybook addon names against the project’s dependencies.storybook/prefer-pascal-case: Require named story exports to use PascalCase.storybook/story-exports: Require every story file to export at least one named story alongside the default meta.storybook/use-storybook-expect: Requireexpectto be imported from@storybook/testin play functions, not from Jest.storybook/use-storybook-testing-library: Reject direct Testing Library imports inside story files.
Rules
storybook/await-interactions
Require await on Storybook interaction helpers (userEvent, expect, waitFor, …) inside a play function.
The interactions addon intercepts the awaited promises to record steps, so a missing await skips that frame in the debugger and races the next assertion.
Example:
export default { component: Button };
export const Primary = {
play: async () => {
// reports: storybook/await-interactions (error)
userEvent.click(button);
},
};storybook/context-in-play-function
Require forwarding the play-function context argument when invoking another story’s play function.
Storybook hangs the canvas, step tracker, and interactions addon off context; omitting it leaves the nested call without the runtime hooks it needs to drive the canvas.
Example:
export default { component: Button };
export const Primary = {};
export const Secondary = {
play: async (context) => {
// reports: storybook/context-in-play-function (error)
Primary.play();
},
};storybook/csf-component
Require the CSF default meta object to declare a component.
The reference unlocks Storybook’s auto-generated controls, prop-table docs, and CSF3 default render, without it those features silently no-op.
Example:
// reports: storybook/csf-component (error)
export default { title: "Atoms/Button" };
export const Primary = {};storybook/default-exports
Require every story file to provide the CSF default export.
Storybook keys all per-file configuration (title, decorators, parameters, component) off that default; files without it are skipped at indexing time.
Example:
// reports: storybook/default-exports (error)
export const Primary = {};storybook/hierarchy-separator
Reject the legacy | separator in Storybook story titles ("Foo|Bar").
Storybook 6 standardized on / for hierarchy and treats | as a literal character, so the title collapses into a single sidebar entry instead of nested folders.
The finding is tagged Deprecated, so an editor strikes the | separator through: the separator is superseded, not broken, and the story still renders.
Example:
export default {
// reports: storybook/hierarchy-separator (warn)
title: "Atoms|Button",
component: Button,
};
export const Primary = {};storybook/meta-inline-properties
Require title and args in CSF meta to be inline literals, not references to outside variables or function calls.
Storybook’s indexer and upgrade codemods read these via static analysis and skip stories where the value is not literal.
Example:
const title = "Atoms/Button";
export default {
// reports: storybook/meta-inline-properties (error)
title,
component: Button,
};
export const Primary = {};storybook/meta-satisfies-type
Require CSF meta objects to type-check with satisfies Meta<...> rather than a : Meta<...> annotation or as cast.
satisfies preserves the narrowed literal types so dependent StoryObj declarations can infer the component’s args precisely.
Example:
// reports: storybook/meta-satisfies-type (error)
export default { component: Button };
export const Primary = {};storybook/no-redundant-story-name
Reject name metadata on a story when it matches Storybook’s auto-derived name from the export identifier.
The explicit value adds boilerplate and drifts from the export when one side is renamed without the other.
The finding is tagged Unnecessary, so an editor greys the annotation out. Both shapes the rule reports are covered: the name / storyName property inside the story object and a standalone Story.storyName = ... assignment. The removable range includes a property’s trailing comma or an assignment’s semicolon, so deleting exactly what is faded leaves valid syntax.
Example:
export default { component: Button };
export const Primary = {
// reports: storybook/no-redundant-story-name (warn)
name: "Primary",
};storybook/no-renderer-packages
Reject direct imports from Storybook renderer packages (@storybook/react, etc.); use the user-facing package surface.
The diagnostic names the framework packages that replace the renderer, and each one is offered as an editor suggestion that rewrites the module specifier. @storybook/react offers @storybook/nextjs, @storybook/react-vite, and @storybook/react-webpack5. None is applied automatically: which one is right depends on the project’s bundler, which the import does not state, so ttsc fix and source.fixAll.ttsc leave the import alone.
Example:
// reports: storybook/no-renderer-packages (error)
import type { Meta } from "@storybook/react";
export default { component: Button };
export const Primary = {};storybook/no-stories-of
Reject the legacy storiesOf(...) builder API.
Storybook 7 removed it in favour of CSF default-export metadata; remaining uses block the migration to CSF3 and the modern indexer.
The finding is tagged Deprecated, so an editor strikes the import specifier through. The instruction is to migrate off the builder, not to delete the import and leave the calls below it unresolved.
Example:
import {
// reports: storybook/no-stories-of (error)
storiesOf,
} from "@storybook/react";
storiesOf("Atoms/Button", module);storybook/no-title-property-in-meta
Reject the title property in CSF meta when the project uses Storybook’s auto-title generation.
CSF3 derives the title from the file path, so an explicit title is redundant and drifts from the on-disk layout when files are moved.
The finding is tagged Unnecessary, so an editor greys the complete removable property out, including its trailing comma when present. Removing exactly the faded range is the resolution and leaves valid object syntax.
Example:
export default {
// reports: storybook/no-title-property-in-meta (error)
title: "Atoms/Button",
component: Button,
};
export const Primary = {};storybook/no-uninstalled-addons
Validate Storybook addon names against the project’s dependencies, so misspelled addon ids surface at lint time.
Options:
-
packageJsonLocation?: stringExplicit
package.jsonpath used to validate configured Storybook addons. When omitted, the rule walks upward from the linted config file. -
ignore?: readonly string[]Addon package names to skip when checking installation status. Default:
[ ].
Example:
export default {
addons: [
"@storybook/addon-links",
// reports: storybook/no-uninstalled-addons (error)
"@storybook/addon-essentials",
],
};storybook/prefer-pascal-case
Require named story exports to use PascalCase.
Storybook derives the displayed story name from the export identifier and inserts spaces at case boundaries, so non-PascalCase exports render with awkward or merged labels in the sidebar.
Example:
export default { component: Button };
// reports: storybook/prefer-pascal-case (warn)
export const primary = {};storybook/story-exports
Require every story file to export at least one named story alongside the default meta.
A file with only the default export contributes nothing to the sidebar and usually means a story was deleted but the file was not.
Example:
// reports: storybook/story-exports (error)
export default { component: Button };
export const __namedExportsOrder = ["Primary"];storybook/use-storybook-expect
Require expect to be imported from @storybook/test in play functions, not from Jest.
The Storybook re-export is built for the browser interactions runner; Jest’s expect ships only Node-only matchers and throws when the play function executes in a browser preview.
Example:
export default { component: Button };
export const Primary = {
play: () => {
// reports: storybook/use-storybook-expect (error)
expect(button).toBeVisible();
},
};storybook/use-storybook-testing-library
Reject direct Testing Library imports inside story files; use the Storybook-bundled re-exports.
Example:
// reports: storybook/use-storybook-testing-library (error)
import { screen } from "@testing-library/react";
export default { component: Button };
export const Primary = {};