Skip to content

UI: Replace IconButton with Button, ToggleButton & Select, add ARIA labels#31702

Closed
Sidnioulz wants to merge 53 commits into
nextfrom
sidnioulz/issue-31261
Closed

UI: Replace IconButton with Button, ToggleButton & Select, add ARIA labels#31702
Sidnioulz wants to merge 53 commits into
nextfrom
sidnioulz/issue-31261

Conversation

@Sidnioulz
Copy link
Copy Markdown
Contributor

@Sidnioulz Sidnioulz commented Jun 7, 2025

Closes #21578
Closes #24073
Closes #31261

Changes to UI

addon-a11y

  • Report: Added aria labels to buttons
  • Tabs: Added aria labels to buttons and reviewed copy
  • VisionSimulator: Ported to be a Select, fixed kb nav and reviewed copy

addon-backgrounds

  • Toolbar: Ported grid button to be a Toggle, added aria label and tooltip
  • Toolbar: Ported background button to be a Select, fixed kb nav, added aria label and tooltip

addon-docs

  • ArgsTable: Added tooltip to reset controls button
  • Toolbar: Added aria labels to zoom buttons
  • Docs: Added stories that showcase the background addon's story override feature as they were missing
  • Controls/Object: Ported "Raw json" button to be a toggle, added aria label, reviewed copy
  • Controls/SaveStory: Fixed up DOM order, reviewed copy for tooltips and aria-labels, simplified code

addon-pseudostates

  • Toolbar: Ported to be a Select with multiSelect, fixed kb nav, added aria labels, reviewed copy

addon-themes

  • Toolbar: Ported to be a Select, fixed kb nav, added aria labels, reviewed copy

addon-vitest

  • ErrorModal: Added tooltip to icon-only Button through use of new Button API
  • TestProviderRender: Improved aria labels on disabled states, switched some buttons to toggles, improved tooltip handling
  • TestingModule: Tooltip and aria label changes throughout, but I uncovered potential discrepancies between the UI and internal state so further work will be needed

addon-interactions

  • Toolbar: Added status role to the status button for rudimentary live reporting (will need review after we have better aria live utils)
  • Toolbar: Added tooltips on all buttons

Mobile layout

  • MobileAbout: Cleaned up UI layout as it had regressed in a previous a11y PR
  • MobileAbout: Added aria label and tooltip to close button
  • MobileNavigation: Removed incorrect use of toolbar role

Notifications

  • Close button: Added aria label and tooltip

Addon panel

  • Toolbar: reviewed copy and added aria labels and tooltips to buttons

Toolbar

  • Added tooltip, reviewed copy for fullscreen, show addon panel, show sidebar buttons
  • Added aria label + tooltip, reviewed copy for copy link, eject, remount, measure, outline, zoom buttons
  • Viewport: Fixed up DOM order and ARIA markup of the viewport tool's dimension switcher
  • Viewport: Ported the button to a Select, added kb nav, aria label, tooltip
  • Addon tools: reworked rendered of declarative addon tools to use a Select

Sidebar

  • Header: Added tooltips for all header buttons
  • Search: Added aria labels and tooltips to clear and filter buttons
  • Testing Module: Reviewed copy on aria labels to try and clarify what they do
  • Tree: Added tooltips to expand/collapse buttons

Onboarding

  • GuidedTour: Added aria label to close button

Settings

  • Added tooltip and label to close page button

Changes to docs

  • Addon writing docs: reworked all examples that involved an IconButton to use Button with the recommended props, and with aria labels

Changes to existing components

Button

  • Added mandatory ariaLabel prop
    • Set to false to convey that the button does not need labelling
    • Set to a string otherwise
  • Added description prop (name TBC) that creates a hidden region for an aria-describedby attr when we want to tell screenreader users how a feature works in more detail
  • Added tooltip prop, set by default to ariaLabel if ariaLabel is not false
  • Added shortcut prop that feeds into aria-keyshortcuts and gets appended to the tooltip for the button
  • Removed active prop as buttons with an active state must convey a specific semantic
    • for now, we have ToggleButton and Select
    • in some places, the active decoration was locally hardcoded until we can move code to matching components like Menu

IconButton

  • Deprecated in favour of Button to avoid having to also introduce ToggleIconButton and ToggleSelect

Modal

  • Close button: added tooltip and keyboard shortcut attribute

New components

InteractiveTooltipWrapper

  • Centralises tooltip behaviour for interactive components: Button, ToggleButton, Select
  • Gives us opportunities to improve DX in the future (e.g. tooltip show on focus, smart delay handling)

ToggleButton

  • Replaces many Buttons with the active prop that toggle a feature on or off
  • The ToggleButton uses a switch role to convey that it is pressed, and requires a pressed boolean prop to bet set.

Select

  • Replaces most buttons in the global toolbar
  • Advertises that it is expandable, and opens a listbox role with options to be selected
  • Standardises layout for current select buttons
  • Adds a standardised "reset" option
  • Implements handmade keyboard navigation to allow single-select Select to act like a native HTML select, and multi-select Select to act like a combobox with a listbox

TO DO

  • Review all Select stories now that the reset prop is implemented
  • Apply CSS on ToggleButton to match @MichaelArested's mockups
  • Apply CSS on Select and MultiSelect to match @MichaelArested's mockups
  • Decide on exact rendering of children for Select and MultiSelect with @MichaelArestad
  • Compute ariaLabel for Select and MultiSelect based on ^
  • Create followup tickets if needed for issues in the testing module and sidebar I couldn't resolve
  • Decide on whether to improve the vocabulary for addon tool declarative selects (missing aria label) (now feeling redundant with title, let's sit on this one a bit and see if anyone actually requests a change)

Known issues

Click behaviour on tooltips

This PR introduces a regression with tooltips. They can no longer be closed by clicking outside. This is due to a Popper limitation to be adressed in #32249

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. Run storybook locally
  2. Browse around, test keyboard nav, test tooltips on hover
  3. Run with NVDA in AssistivLabs and try to use buttons in the toolbar

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 canary-release-pr.yml --field pr=<PR_NUMBER>

Greptile Summary

This PR represents a comprehensive accessibility overhaul of Storybook's UI components, systematically replacing IconButton components with a new unified Button API that enforces proper accessibility through mandatory aria-label props, integrated tooltip functionality, and keyboard shortcut support.

Key Changes

Component Architecture Redesign:

  • Button Component Enhanced: Added mandatory ariaLabel prop (string or false), new shortcut prop for keyboard shortcuts, tooltip prop, and description prop for detailed accessibility information
  • IconButton Deprecated: Replaced with a deprecation wrapper that forwards to Button, eliminating component duplication
  • New Components Introduced: ToggleButton (for binary toggle states with switch role), Select (for dropdown menus with proper keyboard navigation), and InteractiveTooltipWrapper (centralizes tooltip behavior)

Accessibility Improvements:

  • Screen Reader Support: All interactive elements now have proper ARIA labeling through mandatory ariaLabel props
  • Keyboard Navigation: Select components implement full keyboard navigation (arrow keys, Home/End, Page Up/Down) following WCAG guidelines
  • Semantic HTML: ToggleButton uses role="switch" with aria-checked, Select uses role="listbox" with proper option semantics
  • Tooltip Integration: Consolidated tooltip behavior eliminates problematic WithTooltip wrappers that had focus management issues

Migration Impact:

  • 30+ Components Updated: Systematic migration across addons (a11y, docs, vitest, themes, backgrounds, etc.), toolbar components, sidebar elements, and mobile interfaces
  • Documentation Updated: All addon writing examples now demonstrate proper accessibility patterns
  • Breaking Changes: Removed active prop from Button in favor of semantic alternatives, deprecated IconButton

Integration with Existing Codebase

The changes integrate seamlessly with Storybook's component ecosystem by:

  • Maintaining visual consistency through variant and padding props that replicate previous IconButton styling
  • Preserving all existing functionality while adding accessibility layers
  • Using the established manager-api patterns for global state management
  • Following Storybook's theming system for consistent styling across light/dark modes

Confidence score: 4/5

  • This PR significantly improves accessibility compliance and addresses critical keyboard navigation issues, making it safer to merge than the current inaccessible state
  • Score reflects the comprehensive nature of changes across 80+ files, though the systematic approach and thorough testing reduce risk
  • Pay close attention to the new Select component implementation and InteractiveTooltipWrapper as they introduce new interaction patterns that need validation

@Sidnioulz Sidnioulz marked this pull request as draft June 7, 2025 21:51
@Sidnioulz Sidnioulz requested a review from ghengeveld June 7, 2025 21:52
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

48 file(s) reviewed, 5 comment(s)
Edit PR Review Bot Settings | Greptile

Comment thread code/addons/onboarding/src/features/GuidedTour/Tooltip.tsx
Comment thread code/core/src/component-testing/components/InteractionsPanel.tsx
Comment thread code/core/src/component-testing/components/Subnav.tsx Outdated
Comment thread code/core/src/components/components/Button/Button.tsx Outdated
Comment thread code/core/src/manager-api/lib/shortcut.ts
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Jun 7, 2025

View your CI Pipeline Execution ↗ for commit 763dfd8

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 46s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-05 09:56:30 UTC

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-31261 branch from 22cc7dc to 104d77f Compare June 8, 2025 14:25
@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-31261 branch from 4b137a4 to f1b8117 Compare June 22, 2025 09:36
Comment thread code/addons/a11y/src/components/VisionSimulator.tsx Outdated
Comment thread code/core/src/components/components/tooltip/InteractiveTooltipWrapper.tsx Outdated
Comment thread code/core/src/components/components/Button/Button.tsx
@MichaelArestad
Copy link
Copy Markdown
Contributor

MichaelArestad commented Aug 1, 2025

To do for me:

  • mockups
    • button
    • toggleButton
    • select
    • select menu

Comment thread code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx Outdated
Comment thread code/addons/docs/src/blocks/controls/Object.tsx Outdated
@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-31261 branch from fc44f9f to 2e6537d Compare August 6, 2025 14:25
Comment thread code/addons/docs/src/blocks/controls/Object.tsx Outdated
Comment thread code/addons/docs/src/blocks/controls/Object.tsx Outdated
Comment thread code/addons/a11y/src/components/Tabs.tsx Outdated
Comment thread code/addons/themes/src/theme-switcher.tsx
Comment thread code/core/src/backgrounds/components/Tool.tsx Outdated
Comment thread code/core/src/backgrounds/components/Tool.tsx Outdated
Comment thread code/core/src/components/components/Select/Select.tsx Outdated
Comment thread code/core/src/manager/components/preview/tools/copy.tsx Outdated
Comment thread code/core/src/manager/components/preview/tools/eject.tsx Outdated
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Sep 3, 2025

Package Benchmarks

Commit: 763dfd8, ran on 5 September 2025 at 09:48:54 UTC

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

storybook

Before After Difference
Dependency count 48 48 0
Self size 30.74 MB 30.78 MB 🚨 +39 KB 🚨
Dependency size 17.61 MB 17.61 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 204 204 0
Self size 879 KB 879 KB 0 B
Dependency size 81.72 MB 81.76 MB 🚨 +39 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 173 173 0
Self size 35 KB 35 KB 0 B
Dependency size 76.79 MB 76.83 MB 🚨 +39 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 49 49 0
Self size 1.52 MB 1.52 MB 🎉 -30 B 🎉
Dependency size 48.35 MB 48.39 MB 🚨 +39 KB 🚨
Bundle Size Analyzer node node

@Sidnioulz Sidnioulz dismissed MichaelArestad’s stale review September 3, 2025 23:30

We've since had several work sessions and cleaned up an enormous amount of issues :)

@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-31261 branch from da4db5f to 268805e Compare September 4, 2025 12:17
@Sidnioulz Sidnioulz force-pushed the sidnioulz/issue-31261 branch from 268805e to 3a794d4 Compare September 4, 2025 13:07
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Sep 5, 2025

Fails
🚫 PR is marked with "ci: do not merge" label.

Generated by 🚫 dangerJS against 763dfd8

@ghengeveld
Copy link
Copy Markdown
Member

ghengeveld commented Sep 5, 2025

I added ci: do not merge because we want to wrap up our supercycle (2 weeks remaining) before merging this PR, due to it being potentially disruptive. The label may be removed after September 15.

@Sidnioulz
Copy link
Copy Markdown
Contributor Author

I added ci: do not merge because we want to wrap up our supercycle (2 weeks remaining) before merging this PR, due to it being potentially disruptive. The label may be removed after September 15.

Sure thing!

I wanted to squash this PR anyway due to the high amount of low-quality commit messages. Just noting it here to have a trace when the time comes.

@ghengeveld could we consider merging to an a11y-consolidation branch in the meantime though? And then integrating that branch onto next after the supercycle freeze? It would help me regroup the stranded CI issues and actually test all the toolbar/tabbar/button/tooltip elements together.

@ghengeveld
Copy link
Copy Markdown
Member

@Sidnioulz Yes, sounds like a good idea to merge your a11y work into a single branch so we can merge it all in one go.

@Sidnioulz
Copy link
Copy Markdown
Contributor Author

Closing the PR as code was manually applied to https://github.com/storybookjs/storybook/tree/a11y-consolidation.

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

Labels

accessibility bug ci: do not merge ci:normal Run our default set of CI jobs (choose this for most PRs). ui

Projects

None yet

5 participants