Skip to content

Addon-Docs: Scope slugger to docs render#34271

Merged
JReinhold merged 12 commits into
storybookjs:nextfrom
ia319:bug/34198-scope-docs-slugger-to-docs-render
Apr 27, 2026
Merged

Addon-Docs: Scope slugger to docs render#34271
JReinhold merged 12 commits into
storybookjs:nextfrom
ia319:bug/34198-scope-docs-slugger-to-docs-render

Conversation

@ia319
Copy link
Copy Markdown
Member

@ia319 ia319 commented Mar 23, 2026

Closes #34198

What I did

I believe this is a bug; it could result in:

  • the same content lacking a stable URL
  • deep links and anchors behaving unreliably

change:

  • scope docs heading slug generation to each docs render
  • add a docs-scoped slugger context and matching global typings
  • update heading and subheading blocks to consume the scoped slugger
  • preserve slug deduping within a single docs page and the singleton fallback outside docs trees

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

due to Issue #33944, before running, must first delete code/node_modules/.cache.

  1. Run cd code && yarn storybook:ui
  2. Open http://localhost:6006/?path=/docs/example-button--docs
  3. Click Primary and verify the URL hash is #primary
  4. Navigate away and return to Button > Docs
  5. Click Primary again and verify the URL hash is still #primary

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

  • Refactor

    • Heading and subheading anchor IDs are now context-aware, ensuring consistent in-page anchors within documentation pages while preserving existing behavior outside the docs tree.
    • The docs render tree now provides a scoped anchor-generation provider to stabilize anchor IDs across the page.
  • Chores

    • Improved type safety for global docs context and preview URL declarations.

- create a docs-scoped slugger context
- preserve slug deduping within a single docs page
- keep heading anchors stable across docs navigation
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ed85637f-d715-46f6-8e9c-00b10f9de11d

📥 Commits

Reviewing files that changed from the base of the PR and between 4c8cf5b and e9b8477.

📒 Files selected for processing (2)
  • code/addons/docs/src/blocks/blocks/DocsContext.ts
  • code/addons/docs/src/typings.d.ts
✅ Files skipped from review due to trivial changes (2)
  • code/addons/docs/src/typings.d.ts
  • code/addons/docs/src/blocks/blocks/DocsContext.ts

📝 Walkthrough

Walkthrough

Adds a DocsSlugger type, factory, and React context; provides a memoized slugger from DocsContainer; Heading and Subheading consume the context for slug/id generation with fallback to the legacy singleton; refines DocsContext and global typings.

Changes

Cohort / File(s) Summary
Slugger Context (new)
code/addons/docs/src/blocks/blocks/DocsSluggerContext.ts
Adds DocsSlugger type alias, createDocsSlugger() factory, and DocsSluggerContext React context (nullable).
Container Provider
code/addons/docs/src/blocks/blocks/DocsContainer.tsx
Creates a memoized slugger via createDocsSlugger() and wraps the docs render tree with DocsSluggerContext.Provider, placing the existing DocsContext.Provider inside it.
Heading Components
code/addons/docs/src/blocks/blocks/Heading.tsx, code/addons/docs/src/blocks/blocks/Subheading.tsx
Resolve slugger via useContext(DocsSluggerContext) and use it to generate heading ids; retain fallback to the slugs singleton and existing disableAnchor / non-string children behavior.
Docs Context
code/addons/docs/src/blocks/blocks/DocsContext.ts
Initializes DocsContext with explicit generic DocsContextProps<Renderer> using createContext<...>(null!), aligning runtime initialization with the exported typed Context.
Type Definitions
code/addons/docs/src/typings.d.ts
Narrows globals: __DOCS_CONTEXT__ typed as React.Context<DocsContextProps<Renderer>> and PREVIEW_URL changed to `string

Sequence Diagram(s)

sequenceDiagram
  participant DocsContainer as DocsContainer
  participant Provider as DocsSluggerContext.Provider
  participant Slugger as GithubSlugger
  participant Heading as Heading/Subheading

  DocsContainer->>Provider: useMemo(createDocsSlugger()) → provide slugger instance
  Provider->>Slugger: holds DocsSlugger instance
  Heading->>Provider: useContext(DocsSluggerContext)
  alt context present
    Heading->>Slugger: slug(children.toLowerCase()) → id
  else no context
    Heading->>Slugger: use legacy `slugs` singleton → slug → id
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
code/addons/docs/src/blocks/blocks/Docs.tsx (1)

27-27: Consider memoizing the slugger to preserve slug state across re-renders.

The slugger is recreated on every render of Docs. If this component re-renders (e.g., due to context or prop changes), headings would regenerate their IDs from a fresh slugger, potentially causing anchor instability within a single page view.

♻️ Proposed fix using useMemo
+import { useMemo } from 'react';
+
 export function Docs<TRenderer extends Renderer = Renderer>({
   context,
   docsParameter,
 }: DocsProps<TRenderer>) {
   const Container: ComponentType<
     PropsWithChildren<{ context: DocsContextProps<TRenderer>; theme: Theme }>
   > = docsParameter.container || DocsContainer;
 
   const Page = docsParameter.page || DocsPage;
-  const slugger = createDocsSlugger();
+  const slugger = useMemo(() => createDocsSlugger(), []);
 
   return (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/docs/src/blocks/blocks/Docs.tsx` at line 27, The slugger created
by createDocsSlugger() is recreated on each render of the Docs component,
causing unstable heading IDs; memoize it using React's useMemo so the slugger
instance persists across re-renders (and optionally reset when the page changes
by including a page identifier like location.pathname in the dependency array).
Update the slugger declaration in the Docs component to use useMemo(() =>
createDocsSlugger(), [/* optional page key */]) and ensure useMemo is imported
from React.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/addons/docs/src/blocks/blocks/Docs.tsx`:
- Line 27: The slugger created by createDocsSlugger() is recreated on each
render of the Docs component, causing unstable heading IDs; memoize it using
React's useMemo so the slugger instance persists across re-renders (and
optionally reset when the page changes by including a page identifier like
location.pathname in the dependency array). Update the slugger declaration in
the Docs component to use useMemo(() => createDocsSlugger(), [/* optional page
key */]) and ensure useMemo is imported from React.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 80719a5f-4b5c-4ef5-ab44-8ca1fe7506f1

📥 Commits

Reviewing files that changed from the base of the PR and between cd857b9 and 9b82a80.

📒 Files selected for processing (5)
  • code/addons/docs/src/blocks/blocks/Docs.tsx
  • code/addons/docs/src/blocks/blocks/DocsSluggerContext.ts
  • code/addons/docs/src/blocks/blocks/Heading.tsx
  • code/addons/docs/src/blocks/blocks/Subheading.tsx
  • code/addons/docs/src/typings.d.ts

@valentinpalkovic valentinpalkovic moved this to Empathy Queue (prioritized) in Core Team Projects Mar 24, 2026
Copy link
Copy Markdown
Contributor

@JReinhold JReinhold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Added a few suggestions.

Comment thread code/addons/docs/src/blocks/blocks/DocsSluggerContext.ts Outdated
Comment thread code/addons/docs/src/blocks/blocks/Docs.tsx Outdated
@JReinhold JReinhold self-assigned this Mar 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/addons/docs/src/blocks/blocks/DocsContainer.tsx`:
- Line 29: DocsContainer currently calls createDocsSlugger() on every render
which recreates the GithubSlugger and breaks deduplication/causes context
identity churn; change the slugger instantiation to be stable (e.g. use useMemo
or useRef) and only recreate it when the docs page identity changes (use a
stable dependency such as the docs page identifier or the provided context), so
update the slugger creation (the slugger constant created from
createDocsSlugger) to use a memoized/ref value with a dependency like the page
id or context instead of recreating it every render.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 556d3704-f817-4128-a46c-57d1bba18a85

📥 Commits

Reviewing files that changed from the base of the PR and between 50c040f and c424d4a.

📒 Files selected for processing (1)
  • code/addons/docs/src/blocks/blocks/DocsContainer.tsx

Comment thread code/addons/docs/src/blocks/blocks/DocsContainer.tsx Outdated
Copy link
Copy Markdown
Contributor

@JReinhold JReinhold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good now! ❤️ There are some formatting errors and some type errors that is blocked in CI, but once those are fixed it should be ready to go. 🙏

@ia319
Copy link
Copy Markdown
Member Author

ia319 commented Apr 22, 2026

This looks good now! ❤️ There are some formatting errors and some type errors that is blocked in CI, but once those are fixed it should be ready to go. 🙏

🎉 This error doesn't seem like something I need to fix, right? Thanks for confirming

@JReinhold
Copy link
Copy Markdown
Contributor

The type error is coming from this new code, so yeah I think you need to fix it. Sorry that I didn't make that clear. 😞

https://app.circleci.com/pipelines/github/storybookjs/storybook/120814/workflows/79b9b7cc-1d2e-4104-93b8-c8d3578d31e6/jobs/1392939?invite=true#step-111-26378_58

You can run yarn task check --no-link to run the full type check across all packages.

@storybook-app-bot
Copy link
Copy Markdown

Package Benchmarks

Commit: e9b8477, ran on 23 April 2026 at 18:03:43 UTC

The following packages have significant changes to their size or dependencies:

@storybook/builder-webpack5

Before After Difference
Dependency count 186 186 0
Self size 76 KB 76 KB 🎉 -48 B 🎉
Dependency size 32.78 MB 32.89 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 185 185 0
Self size 140 KB 140 KB 🎉 -54 B 🎉
Dependency size 30.44 MB 30.54 MB 🚨 +106 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 190 190 0
Self size 15 KB 15 KB 🎉 -18 B 🎉
Dependency size 29.50 MB 29.61 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 535 535 0
Self size 650 KB 650 KB 0 B
Dependency size 60.80 MB 60.91 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 273 273 0
Self size 23 KB 23 KB 0 B
Dependency size 45.41 MB 45.52 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 198 198 0
Self size 16 KB 16 KB 0 B
Dependency size 34.04 MB 34.15 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-react-webpack

Before After Difference
Dependency count 166 166 0
Self size 18 KB 18 KB 🎉 -24 B 🎉
Dependency size 31.78 MB 31.89 MB 🚨 +111 KB 🚨
Bundle Size Analyzer Link Link

@ia319
Copy link
Copy Markdown
Member Author

ia319 commented Apr 23, 2026

@JReinhold I made a small fix, and the checks have passed now.

@JReinhold JReinhold moved this from Empathy Queue (prioritized) to In Progress in Core Team Projects Apr 27, 2026
@JReinhold JReinhold merged commit c87c654 into storybookjs:next Apr 27, 2026
119 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Core Team Projects Apr 27, 2026
@github-actions github-actions Bot mentioned this pull request Apr 27, 2026
16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: Auto-docs adds number suffix to headings and increases it for each page visit

4 participants