Skip to content

Conversation

@Sidnioulz
Copy link
Member

@Sidnioulz Sidnioulz commented Jan 2, 2026

Closes #33453

What I did

Created an accessibility statement page, ahead of the blog post on accessibility, so we can reference it.

  • Added an accessibility statement page
  • Added a link to the page in the settings menu and tablist
  • Added a link to the page in the mobile sidebar heading
  • Cleaned up some mobile sidebar prop drilling in favour of already-in-use useLayout hook
  • Added stories for mobile version of the sidebar Menu

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

  1. Open Storybook
  2. In desktop mode, in sidebar settings menu, click Accessibility statement
  3. In mobile mode, open the sidebar and click the accessibility icon
image image image image

Documentation

ø

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

Release Notes

  • New Features
    • Added a comprehensive accessibility statement detailing conformance, accessibility measures, feedback channels, compatibility information, and technical specifications.
    • Accessibility statement now accessible via a new link in the sidebar and a dedicated button in the mobile menu.
    • New settings tab for quick access to the accessibility statement.

✏️ Tip: You can customize this high-level summary in your review settings.

@nx-cloud
Copy link

nx-cloud bot commented Jan 2, 2026

View your CI Pipeline Execution ↗ for commit c296c2e

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 8m 23s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-02 16:39:55 UTC

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 2, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive accessibility statement feature to Storybook, including new UI components for desktop and mobile views, layout state management for mobile panel visibility, menu and sidebar integration, a settings page for the accessibility statement, and corresponding Storybook stories for testing.

Changes

Cohort / File(s) Summary
Accessibility Statement Components
A11yStatement.tsx, A11yStatementPage.tsx
Two new components rendering accessibility statement content with styled UI elements, keyboard shortcut displays, and typography-based layout for both component-level reuse and full settings page display.
Mobile Accessibility Statement
MobileA11yStatement.tsx, MobileA11yStatement.stories.tsx
New mobile panel component with slide animations and back button, plus full Storybook story setup with light/dark theme variants and programmatic open/close testing.
Layout State Management
LayoutProvider.tsx
Added isMobileA11yStatementOpen boolean state and setMobileA11yStatementOpen setter to layout context, exposed through context value and dependency arrays.
Mobile Navigation Integration
MobileMenuDrawer.tsx
MobileA11yStatement component now rendered inside drawer modal alongside children.
Sidebar and Heading Components
Sidebar.tsx, Heading.tsx, Menu.tsx (components/)
Removed onMenuClick prop across Sidebar and Heading; added a11yStatementHref prop to Heading for conditional accessibility statement link rendering; Menu.tsx updated with AccessibilityIcon import and mobile button to trigger setMobileA11yStatementOpen.
Sidebar Stories
Heading.stories.tsx, Menu.stories.tsx
Added AccessibilityStatementLinkFocused story for Heading; four new mobile-layout stories (Mobile, MobileA11yStatement, MobileAbout, MobileClose) in Menu.stories with state toggle verification.
Menu Configuration
Menu.tsx (container/), Sidebar.tsx (container/)
New accessibility statement menu item with AccessibilityIcon added to menu structure; removed onMenuClick prop and SidebarProps import from SidebarContainer.
Settings Integration
settings/index.tsx
New "Accessibility statement" route added to settings tabs, rendering A11yStatementPage at path "accessibility-statement".
App Root
App.tsx
Removed useLayout import and onMenuClick handler; Sidebar no longer receives onMenuClick prop.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Menu
    participant LayoutProvider
    participant MobileA11yStatement
    participant Settings/Router
    participant A11yStatementPage

    rect rgb(200, 220, 255)
    note over User,MobileA11yStatement: Mobile Flow
    User->>Menu: Clicks Accessibility Icon
    Menu->>LayoutProvider: setMobileA11yStatementOpen(true)
    LayoutProvider->>MobileA11yStatement: isMobileA11yStatementOpen = true
    MobileA11yStatement->>MobileA11yStatement: Render with slideFromRight animation
    MobileA11yStatement->>User: Display accessibility statement panel
    User->>MobileA11yStatement: Clicks Back button
    MobileA11yStatement->>LayoutProvider: setMobileA11yStatementOpen(false)
    LayoutProvider->>MobileA11yStatement: Unmount with slideToRight animation
    end

    rect rgb(220, 255, 200)
    note over User,A11yStatementPage: Desktop/Settings Flow
    User->>Menu: Clicks Accessibility Statement menu item
    Menu->>Settings/Router: Navigate to /settings/accessibility-statement
    Settings/Router->>A11yStatementPage: Route activated
    A11yStatementPage->>User: Display accessibility statement page
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • storybookjs/storybook#32458 — Both PRs make overlapping code-level changes to layout context state, sidebar/menu/heading components, and mobile navigation integration for accessibility features.
  • storybookjs/storybook#32795 — Both PRs modify the same sidebar, menu, heading, and layout context files with related state and prop changes.
  • storybookjs/storybook#33140 — Both PRs make direct code changes to sidebar-related Menu.tsx and story files with similar component integration patterns.
✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link
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

🧹 Nitpick comments (3)
code/core/src/manager/components/a11y/A11yStatement.tsx (1)

32-186: Extract the hardcoded date to improve maintainability.

The accessibility statement is well-structured. However, the date on line 184 is hardcoded as a string literal ("2 January 2026"). Consider extracting this to a constant at the top of the file or in a config file to simplify future updates without modifying the component directly.

The browser version numbers on line 87 (Chrome 131, Edge 134, Firefox 136, Safari 18.3, Opera 117) are also hardcoded. If these versions are tied to Storybook's official compatibility policy, consider defining them as a constant to ensure consistency across documentation and code.

code/core/src/manager/components/sidebar/Heading.tsx (1)

97-103: Remove rel="canonical" — it's not semantically appropriate here.

The rel="canonical" attribute is intended for <link> elements in the document <head> to indicate the preferred URL for SEO deduplication. It has no meaningful effect on navigation anchors and may confuse future maintainers.

Additionally, tabIndex={0} is redundant since anchor elements with an href attribute are natively keyboard-focusable.

🔎 Proposed fix
       {a11yStatementHref && (
         <SkipToCanvasLink ariaLabel={false} asChild>
-          <a href={a11yStatementHref} rel="canonical" tabIndex={0}>
+          <a href={a11yStatementHref}>
             Accessibility Statement
           </a>
         </SkipToCanvasLink>
       )}
code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx (1)

63-68: Consider using waitFor instead of hardcoded delay for more reliable tests.

The hardcoded 1000ms delay can be flaky (too short on slow CI) or wasteful (too long when rendering is fast). If this is primarily for Chromatic visual testing, it may be acceptable, but for interaction testing reliability, consider using waitFor.

🔎 Proposed alternative
+import { waitFor, within } from 'storybook/test';
+
 export const Closed: Story = {
   play: async ({ canvasElement }) => {
-    await new Promise((resolve) => setTimeout(resolve, 1000));
-    const closeButton = within(canvasElement).getByText('Back');
-    closeButton.click();
+    const canvas = within(canvasElement);
+    await waitFor(() => canvas.getByText('Back'));
+    const closeButton = canvas.getByText('Back');
+    await closeButton.click();
   },
 };
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f193d3 and c296c2e.

📒 Files selected for processing (15)
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/settings/index.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
🧠 Learnings (10)
📓 Common learnings
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/settings/index.tsx
  • code/core/src/manager/components/layout/LayoutProvider.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
📚 Learning: 2025-10-03T07:55:42.639Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/manager/components/preview/Toolbar.tsx:102-105
Timestamp: 2025-10-03T07:55:42.639Z
Learning: In code/core/src/manager/components/preview/Toolbar.tsx, we intentionally do not add aria-label/aria-labelledby to StyledToolbar (AbstractToolbar) because the enclosing section is already labeled via an sr-only heading and the toolbar is the only content. Revisit only if real user testing indicates a need.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/container/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx
  • code/core/src/manager/settings/A11yStatementPage.tsx
  • code/core/src/manager/components/sidebar/Heading.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
📚 Learning: 2025-11-25T11:09:33.798Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 33140
File: code/core/src/manager/components/sidebar/TagsFilter.tsx:247-259
Timestamp: 2025-11-25T11:09:33.798Z
Learning: In the storybookjs/storybook repository, PopoverProvider creates popovers with a dialog role, so using aria-haspopup="dialog" on buttons that trigger PopoverProvider is semantically correct.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.tsx
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.tsx
  • code/core/src/manager/components/a11y/A11yStatement.tsx
  • code/core/src/manager/components/sidebar/Menu.stories.tsx
  • code/core/src/manager/App.tsx
  • code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
  • code/core/src/manager/container/Sidebar.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/core/src/manager/components/sidebar/Heading.stories.tsx
  • code/core/src/manager/App.tsx
📚 Learning: 2025-10-01T15:24:01.060Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32594
File: code/core/src/components/components/Popover/WithPopover.tsx:7-9
Timestamp: 2025-10-01T15:24:01.060Z
Learning: In the Storybook repository, "react-aria-components/patched-dist/*" (e.g., "react-aria-components/patched-dist/Dialog", "react-aria-components/patched-dist/Popover", "react-aria-components/patched-dist/Tooltip") are valid import paths created by a patch applied to the react-aria-components package. These imports should not be flagged as broken or invalid until a maintainer explicitly states they are no longer acceptable.

Applied to files:

  • code/core/src/manager/components/sidebar/Menu.stories.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: The useGlobals hook from storybook/manager-api returns a tuple where the third element (storyGlobals) is typed as Globals, not Globals | undefined. This means TypeScript guarantees it's always defined, making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/core/src/manager/App.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/core/src/manager/App.tsx
🧬 Code graph analysis (10)
code/core/src/manager/components/sidebar/Menu.tsx (1)
code/core/src/manager/components/layout/LayoutProvider.tsx (1)
  • useLayout (75-75)
code/core/src/manager/container/Menu.tsx (1)
code/core/src/components/components/tooltip/TooltipLinkList.tsx (1)
  • NormalLink (31-37)
code/core/src/manager/components/a11y/A11yStatement.tsx (2)
code/core/src/manager/container/Menu.tsx (1)
  • Shortcut (57-63)
code/core/src/components/index.ts (4)
  • H2 (13-13)
  • H3 (14-14)
  • H4 (15-15)
  • H5 (16-16)
code/core/src/manager/components/sidebar/Heading.stories.tsx (2)
code/frameworks/angular/src/client/public-types.ts (1)
  • StoryObj (45-48)
code/core/src/manager/components/sidebar/Heading.tsx (1)
  • Heading (80-112)
code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx (3)
code/core/src/manager/components/layout/LayoutProvider.tsx (1)
  • useLayout (75-75)
code/core/src/manager/components/a11y/A11yStatement.tsx (1)
  • A11yStatement (188-188)
code/core/src/theming/index.ts (1)
  • keyframes (16-16)
code/core/src/manager/components/sidebar/Menu.stories.tsx (3)
code/core/src/manager/components/layout/LayoutProvider.tsx (2)
  • useLayout (75-75)
  • LayoutProvider (33-73)
code/core/src/manager/components/sidebar/Sidebar.stories.tsx (1)
  • Mobile (211-215)
code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx (1)
  • MobileA11yStatement (15-55)
code/core/src/manager/settings/A11yStatementPage.tsx (1)
code/core/src/manager/components/a11y/A11yStatement.tsx (1)
  • A11yStatement (188-188)
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx (2)
code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx (1)
  • MobileA11yStatement (15-55)
code/core/src/manager/components/sidebar/Menu.stories.tsx (1)
  • MobileA11yStatement (265-279)
code/core/src/manager/components/sidebar/Heading.tsx (1)
code/core/src/manager/components/sidebar/Menu.tsx (2)
  • MenuList (14-14)
  • SidebarMenu (138-200)
code/core/src/manager/settings/index.tsx (1)
code/core/src/manager/settings/A11yStatementPage.tsx (1)
  • A11yStatementPage (21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: nx
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (18)
code/core/src/manager/container/Sidebar.tsx (1)

11-11: LGTM! Clean refactoring removes prop drilling.

The removal of the onMenuClick prop simplifies the component signature and aligns with the shift to using the useLayout hook pattern for managing mobile menu state.

code/core/src/manager/settings/A11yStatementPage.tsx (1)

1-21: LGTM! Well-structured accessibility statement page.

The implementation follows existing Storybook patterns:

  • Proper use of semantic <main> element for the page wrapper
  • Theme-based styling with centered, max-width layout
  • Clean functional component with named export
code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx (1)

9-9: LGTM! Proper integration of mobile accessibility statement.

The MobileA11yStatement component is correctly added to the drawer content and manages its own visibility state via the useLayout hook, keeping the integration clean.

Also applies to: 42-42

code/core/src/manager/settings/index.tsx (1)

15-15: LGTM! Accessibility statement tab properly integrated.

The new settings tab follows the established pattern for other tabs and is correctly wired with:

  • Matching id and route path ('accessibility-statement')
  • Proper RouteWrapper and component rendering
  • Logical placement in the tab order

Also applies to: 90-98

code/core/src/manager/App.tsx (1)

67-67: LGTM! Simplified Sidebar rendering aligns with refactoring.

The removal of the onMenuClick prop is consistent with the refactoring in code/core/src/manager/container/Sidebar.tsx and simplifies the component tree by eliminating prop drilling.

code/core/src/manager/components/sidebar/Menu.tsx (2)

138-141: LGTM! Refactoring to use layout context.

The removal of onClick from SidebarMenuProps and the adoption of the useLayout hook eliminates prop drilling and centralizes mobile state management. The destructuring correctly retrieves all necessary state setters.


146-155: LGTM! Accessibility button properly implemented.

The new accessibility statement button follows the established pattern with proper ariaLabel, correct variant, and appropriate icon. The implementation is consistent with the existing buttons.

code/core/src/manager/container/Menu.tsx (1)

92-101: LGTM! Accessibility statement menu item properly configured.

The new menu item follows the established pattern with proper memoization, correct icon, and appropriate navigation handler. The configuration is consistent with other menu items like about and shortcuts.

code/core/src/manager/components/a11y/A11yStatement.tsx (1)

22-25: LGTM! Proper accessibility label for keyboard shortcuts.

The Shortcut component correctly uses aria-label on the <Kbd> element to provide the raw shortcut key, while displaying the human-readable version. This ensures screen readers announce the actual key name.

code/core/src/manager/components/mobile/a11y/MobileA11yStatement.tsx (2)

15-55: LGTM! Mobile accessibility statement panel properly implemented.

The component correctly:

  • Uses the layout context to manage visibility state
  • Implements smooth enter/exit transitions with useTransitionState
  • Syncs transition state with layout state via useEffect
  • Provides proper close functionality with an accessible button (ariaLabel per convention)
  • Wraps content in a scrollable area

The implementation follows established patterns for mobile panels in the codebase.


57-95: LGTM! Animation implementation is clean and appropriate.

The slide-in/slide-out animations use keyframes correctly and the Container styling properly applies the animation based on transition status. The z-index of 11 is appropriate for a mobile overlay panel.

code/core/src/manager/components/sidebar/Menu.stories.tsx (2)

226-253: LGTM! Well-designed test helpers for mobile stories.

The LayoutContainerPrinter and MobileLayoutProvider components are well-structured for testing mobile layout scenarios:

  • LayoutContainerPrinter displays the current state for verification in play functions
  • MobileLayoutProvider forces mobile mode with forceDesktop={false}
  • The pattern enables visual and automated testing of mobile state changes

255-309: LGTM! Comprehensive mobile story coverage.

The four new stories provide excellent test coverage:

  1. Mobile: Base mobile menu display
  2. MobileA11yStatement: Tests accessibility statement button and state toggle
  3. MobileAbout: Tests about button and state toggle
  4. MobileClose: Tests close button and state toggle

Each story includes appropriate play functions that verify the expected state changes after user interactions.

code/core/src/manager/components/sidebar/Sidebar.tsx (1)

158-165: LGTM!

The a11yStatementHref prop is correctly wired to the settings route, and the removal of onMenuClick prop drilling aligns with the shift to context-based mobile menu handling via useLayout.

code/core/src/manager/components/sidebar/Heading.tsx (1)

109-109: LGTM!

The simplified SidebarMenu props align with the context-based approach where mobile state is obtained via useLayout hook inside SidebarMenu itself.

code/core/src/manager/components/sidebar/Heading.stories.tsx (1)

243-255: LGTM!

The new story follows the established pattern from SkipToCanvasLinkFocused, providing good visual regression coverage for the accessibility statement link focus state.

code/core/src/manager/components/layout/LayoutProvider.tsx (1)

10-11: LGTM!

The new isMobileA11yStatementOpen state follows the established pattern for mobile modal states (isMobileAboutOpen, isMobilePanelOpen). The implementation is consistent and correctly wired into the context.

Also applies to: 23-24, 40-40, 50-51

code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx (1)

20-52: LGTM!

The meta configuration is well-structured with appropriate viewport settings for mobile testing, proper context providers in decorators, and good Chromatic configuration.

Comment on lines +11 to +18
/** A helper component to open the about page via the MobileLayoutContext */
const OpenAboutHelper = ({ children }: { children: any }) => {
const { setMobileA11yStatementOpen } = useLayout();
useEffect(() => {
setMobileA11yStatementOpen(true);
}, [setMobileA11yStatementOpen]);
return children;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the comment — it mentions "about page" but opens the accessibility statement.

The comment appears to be copy-pasted from MobileAbout.stories.tsx and wasn't updated for this context.

🔎 Proposed fix
-/** A helper component to open the about page via the MobileLayoutContext */
+/** A helper component to open the accessibility statement page via the LayoutContext */
 const OpenAboutHelper = ({ children }: { children: any }) => {

Also consider renaming the component to OpenA11yStatementHelper for clarity.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** A helper component to open the about page via the MobileLayoutContext */
const OpenAboutHelper = ({ children }: { children: any }) => {
const { setMobileA11yStatementOpen } = useLayout();
useEffect(() => {
setMobileA11yStatementOpen(true);
}, [setMobileA11yStatementOpen]);
return children;
};
/** A helper component to open the accessibility statement page via the LayoutContext */
const OpenAboutHelper = ({ children }: { children: any }) => {
const { setMobileA11yStatementOpen } = useLayout();
useEffect(() => {
setMobileA11yStatementOpen(true);
}, [setMobileA11yStatementOpen]);
return children;
};
🤖 Prompt for AI Agents
In code/core/src/manager/components/mobile/a11y/MobileA11yStatement.stories.tsx
around lines 11-18, the top comment incorrectly says "about page" though the
helper opens the accessibility statement; update the comment to accurately
describe that the component opens the mobile accessibility statement (e.g., "A
helper component to open the mobile accessibility statement via the
MobileLayoutContext"), and optionally rename the component from OpenAboutHelper
to OpenA11yStatementHelper (and update all references/usages and the export
name) to reflect its purpose.

@storybook-app-bot
Copy link

Package Benchmarks

Commit: c296c2e, ran on 2 January 2026 at 16:38:03 UTC

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

storybook

Before After Difference
Dependency count 49 49 0
Self size 20.19 MB 20.21 MB 🚨 +13 KB 🚨
Dependency size 16.52 MB 16.52 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 183 183 0
Self size 775 KB 775 KB 🚨 +84 B 🚨
Dependency size 67.24 MB 67.26 MB 🚨 +13 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 176 176 0
Self size 30 KB 30 KB 🚨 +36 B 🚨
Dependency size 65.82 MB 65.83 MB 🚨 +13 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 50 50 0
Self size 999 KB 999 KB 🎉 -42 B 🎉
Dependency size 36.71 MB 36.72 MB 🚨 +13 KB 🚨
Bundle Size Analyzer node node

@Sidnioulz
Copy link
Member Author

@kylegach @jonniebigodes happy to hear from you folks on the content of the actual page. There is some normative aspect to it (what we conform to, what requirements we have) but feel free to work your magic on wording!

@MichaelArestad
Copy link
Contributor

From a discussion with Steve:

High-level goal: This statement needs to be reachable.

Notes/thoughts:

  • It feels like it would be in a similar category to "Terms of Service" or "Privacy policy"
  • Perhaps we could add it to a footer of the about page.

Open questions:

  1. Does the link to it need to be in the cog menu?
  2. Does it have to be a view on every Storybook?
    a. Could it instead be a statement hosted on the SB marketing site?

@Sidnioulz
Copy link
Member Author

@vanessayuenn:

Some users may need to disable this because they have their own a11y compliance commitments validated by their org / have their own a11y statement page.

@ghengeveld
Copy link
Member

ghengeveld commented Jan 9, 2026

I think this needs to be opt-in and customizable. It feels wrong to slap a legal document on everyone's Storybooks without them / their legal team explicitly opting in.

I also think the cog menu is too prominent. A link in the footer of the about page feels more appropriate. After all, this doc is useless 99% of the time. There just needs to be some way to access it.

I do think it needs to be shipped along with Storybook rather than be an external resource, in order to ensure proper versioning, and support potential customization.

I wonder if this should just be a markdown file in the static dir, which we then link to, rather than a full-blown React component. E.g. ACCESSIBILITY.md and if it exists, we show a link to it. We could support .html as well, for people who want to get fancy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accessibility ci:normal maintenance User-facing maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[A11y]: Write accessibility statement

4 participants