Automatically generate clean, human-readable Storybook sidebar titles from your file structure.
Storybook Auto Titles
Human-readable, automatically generated Storybook sidebar titles — zero per-story boilerplate.
Automatically transform Storybook’s implicit auto-titles into clean, readable, hierarchical groups based on your file structure.
Support Me
If you find the this useful, consider:
- Donating Ko-fi: https://ko-fi.com/deniszholob
- Supporting on Patreon: https://www.patreon.com/deniszholob
🧩 Example
See https://deniszholob.github.io/storybook-auto-title/ for example storybook deployment
With @deniszholob/storybook-auto-titles
Components/Generic/Badge
Default Storybook titles
Components/generic/badge/badge.component/Badge
File tree
src/app/components/generic/badge/badge.component.stories.ts
📦 Installation
From npm
pnpm add -D @deniszholob/storybook-auto-titles
# or
npm i -D @deniszholob/storybook-auto-titles
# or
yarn add -D @deniszholob/storybook-auto-titles
Local install (no npm registry)
Download release asset https://github.com/deniszholob/storybook-auto-title/releases
pnpm add -D storybook-auto-titles-<version>.tgz
🚀 Usage
.storybook/main.ts
import { autoTitleIndexer, AutoTitleOptions } from '@deniszholob/storybook-auto-titles';
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
experimental_indexers: autoTitleIndexer({
// Config Options
} satisfies AutoTitleOptions),
};
export default config;
For MDX docs, prefer attached docs with Meta of={...} so the docs page inherits the same auto-title path as its story file.
⚙️ Configuration
experimental_indexers: autoTitleIndexer({
stripPrefixes: ['libs/', 'src/app/'],
dedupeAdjacent: true,
stripSegmentSuffixes: ['widget'],
stripSegmentSuffixesMode: 'add',
});
Config Options
| Option | Type | Default | Description |
|---|---|---|---|
| stripPrefixes | string[] |
[] |
Removes leading path segments before processing |
| dedupeAdjacent | boolean |
true |
Removes repeated adjacent folder names |
| segmentTransform | (segment) => string |
Title Case | Custom label formatter |
| flattenTitle | (title) => string |
internal | Full override for custom pipelines |
| stripSegmentSuffixes | string[] |
[] |
Extra or replacement suffixes to strip (without leading .) |
| stripSegmentSuffixesMode | 'add' | 'replace' |
'add' |
add merges with defaults; replace uses only your list |
Default stripped suffixes include Angular + Storybook values:
component, directive, service, pipe, module, guard, resolver, interceptor, stories, story.
Story names are also synced with the story file suffix:
- if suffix is stripped,
Tooltip DirectivebecomesTooltip - if suffix is not stripped (for example replace with
[]),TooltipbecomesTooltip Directive - if a raw name still looks like a filename, it is humanized automatically
✨ Features
- ✅ Storybook 8, 9, and 10+ compatible (storybook versions with experimental_indexers)
- ✅ Framework agnostic (Angular, React, Vue, Web Components, etc.)
- ✅ Keeps Storybook’s auto-title logic (uses
makeTitle) - ✅ Converts kebab-case / snake_case / dotted names → Title Case
- ✅ Removes noisy suffixes like
.component,.directive,.service,.stories, etc... - ✅ Keeps story names in sync with suffix stripping rules
- ✅ Preserves nested component folders when child folders also contain stories/docs
- ✅ Deduplicates repeated path segments
- ✅ Optional prefix stripping (
src/app,libs/ui, etc.) - ✅ No changes required in your story files
- ✅ ESM + CJS compatible
- ✅ Monorepo and Nx friendly
🧠 Why this exists
Without this, you would either:
- manually setting
titlein every story to achieve pretty title (hard to manage) - use the defaults (not as friendly, and requires more clicks)
🏗 How it works
We hook into Storybook’s experimental indexer API and:
- Ask Storybook for the correct implicit title via
options.makeTitle() - Transform the result into a human-readable hierarchy
- Sync raw story names with the file suffix when needed
- Remove stale
__idvalues so HMR and CSF imports stay stable


