feat: Add expandable step navigation for narrow viewports in Wizard Component#4200
feat: Add expandable step navigation for narrow viewports in Wizard Component#4200
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4200 +/- ##
==========================================
+ Coverage 97.18% 97.25% +0.07%
==========================================
Files 883 888 +5
Lines 25866 26050 +184
Branches 9344 9448 +104
==========================================
+ Hits 25137 25336 +199
+ Misses 723 708 -15
Partials 6 6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
src/wizard/__integ__/wizard.test.ts
Outdated
|
|
||
| // Collapsed steps container should exist at narrow viewport | ||
| // Note: Using attribute selector because CSS class names are hashed in the build output | ||
| // Using isExisting() because ExpandableSection header has screenreader-only styling when collapsed |
There was a problem hiding this comment.
Hmm, that doesn't sound right to me. Are you sure you can't use isDisplayed() here? The expandable section header is always visible, so it doesn't use screenreader-only styling.
And instead of relying on [class*=...], you can use the exact selectors directly from the style file. Check the unit tests for how we import it; it's find to do in the integ tests too.
const collapsedSteps = wizardWrapper.find(styles['collapsed-steps']).findExpandableSection().toSelector();Same for the sidebar navigation.
There was a problem hiding this comment.
Done - using isDisplayed() and importing styles directly from styles.selectors.js
src/wizard/__tests__/wizard.test.tsx
Outdated
| // Helper to mock mobile viewport for useMobile() hook | ||
| const mockMobileViewport = () => { | ||
| const originalMatchMedia = window.matchMedia; | ||
| window.matchMedia = jest.fn().mockImplementation(query => ({ | ||
| matches: query.includes('max-width'), | ||
| media: query, | ||
| onchange: null, | ||
| addListener: jest.fn(), | ||
| removeListener: jest.fn(), | ||
| addEventListener: jest.fn(), | ||
| removeEventListener: jest.fn(), | ||
| dispatchEvent: jest.fn(), | ||
| })); | ||
| return () => { | ||
| window.matchMedia = originalMatchMedia; | ||
| }; | ||
| }; | ||
|
|
There was a problem hiding this comment.
It's better to just mock useMobile entirely rather than the underlying implementation. It's also simpler to manage since you just need to change true/false.
jest.mock('../../../lib/components/internal/hooks/use-mobile', () => ({
...jest.requireActual('../../../lib/components/internal/hooks/use-mobile'),
useMobile: jest.fn().mockReturnValue(true),
}));There was a problem hiding this comment.
Done - now mocking useContainerBreakpoints directly instead of window.matchMedia.
src/wizard/internal.tsx
Outdated
| const ref = useMergeRefs(breakpointsRef, __internalRootRef); | ||
|
|
||
| const smallContainer = breakpoint === 'default'; | ||
| const isMobile = useMobile(); |
There was a problem hiding this comment.
This is a change in implementation; did we talk about doing this? useMobile is a global hook, so it returns true/false depending on the width of the viewport. useContainerBreakpoints is a container hook, so it changes depends on the width of the wizard itself.
For example, take a look at the playground page for wizard. It switches to mobile even before the page goes to mobile size because the wizard is in a small container.
There was a problem hiding this comment.
This was raised as a bug during bug bash. When resizing the viewport, the Wizard collapses to mobile steps first, then a few pixels later AppLayout switches to mobile - creating a jarring staggered effect.
This happens because Wizard uses useContainerBreakpoints() (triggers earlier as container shrinks) while AppLayout uses useMobile() (triggers at viewport breakpoint).
Which behavior should we prioritize?
- (A) Keep container-based: Preserves narrow-container collapse, but Wizard collapses before AppLayout
- (B) Switch to viewport-based: Syncs with AppLayout collapse timing, but loses narrow-container collapse
There was a problem hiding this comment.
I don't think it's so important for the responsive logic to smoothly transition from big to small screen and never go up again — the idea behind container queries is so that it switches depending on both the screen size and if panels are toggled, which is more of a common action.
I would prefer not making the change in the PR and independently checking with a designer — there's a reason we have container queries in a number of components, especially when the available width on a page can change so frequently (especially now, with left panels, right panels, bottom panels, etc)
There was a problem hiding this comment.
I've reverted the change back to useContainerBreakpoints. The container-responsive behavior is preserved - Wizard will collapse based on its own container width, not the viewport.
I'll mark this bug bash issue as "works as designed" and note that it needs designer input if we want to revisit the transition timing between AppLayout and Wizard.
|
|
||
| <span className={clsx(styles.number, styles['navigation-link-label'])}> | ||
| {i18nStrings.stepNumberLabel?.(index + 1)} | ||
| {step.isOptional && <i id={optionalDescriptionId}>{` - ${i18nStrings.optional}`}</i>} |
Description
Adds an expandable step navigation for the Wizard component that appears on narrow viewports (< 688px).
Changes
WizardStepNavigationExpandablecomponent: Displays step navigation inside an expandable section when the sidebar is hidden on narrow viewportsWizardStepListcomponent: Shared step list rendering with grid-based layout matching the desktop sidebar visual style (circles, connecting lines, step labels)getStepStatus,handleStepNavigation,canSkipfunctions extracted for reuse between desktop and expandable navigation<nav>landmark wrapper withheaderAriaLabelprop support for screen readersInternalWizardBildschirmaufnahme.2026-02-04.um.08.52.46.mov
Related links, issue #, if available:
AWSUI-19175How has this been tested?
Review checklist
The following items are to be evaluated by the author(s) and the reviewer(s).
Correctness
CONTRIBUTING.md.CONTRIBUTING.md.Security
checkSafeUrlfunction.Testing
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.