Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/@adobe/react-spectrum/src/steplist/StepListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function StepListItem<T>(props: SpectrumStepListItemProps<T>): ReactNode
}

let markerId = useId();
let stateId = useId();
let labelId = useId();

return (
Expand All @@ -78,7 +79,7 @@ export function StepListItem<T>(props: SpectrumStepListItemProps<T>): ReactNode
<FocusRing within focusRingClass={classNames(styles, 'focus-ring')}>
<a
{...mergeProps(hoverProps, stepProps)}
aria-labelledby={`${markerId} ${labelId}`}
aria-labelledby={`${markerId} ${stateId} ${labelId}`}
ref={ref}
className={classNames(
styles,
Expand All @@ -91,7 +92,7 @@ export function StepListItem<T>(props: SpectrumStepListItemProps<T>): ReactNode
'is-selectable': state.isSelectable(key) && !isSelected
}
)}>
<VisuallyHidden {...stepStateProps}>{stepStateText}</VisuallyHidden>
<VisuallyHidden {...stepStateProps} id={stateId}>{stepStateText}</VisuallyHidden>
<div id={labelId} aria-hidden="true" className={classNames(styles, 'spectrum-Steplist-label')}>
{item.rendered}
</div>
Expand Down
32 changes: 32 additions & 0 deletions packages/@adobe/react-spectrum/test/steplist/StepList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,38 @@ describe('StepList', function () {
expect(stepList).toHaveAttribute('id', 'steplist-id');
});

it('includes step state text in the accessible name via aria-labelledby', function () {
const tree = renderComponent({defaultLastCompletedStep: 'step-two', defaultSelectedKey: 'step-three', onSelectionChange});
const stepListItems = tree.getAllByRole('link');

// Each link should have an aria-labelledby referencing marker, state, and label IDs
for (let link of stepListItems) {
let labelledby = link.getAttribute('aria-labelledby');
expect(labelledby).toBeTruthy();
let ids = labelledby!.split(' ');
expect(ids).toHaveLength(3);
for (let id of ids) {
expect(document.getElementById(id)).toBeTruthy();
}
}

// Verify the step state text is included in referenced elements
let currentStep = stepListItems[2];
let currentIds = currentStep.getAttribute('aria-labelledby')!.split(' ');
let stateEl = document.getElementById(currentIds[1]);
expect(stateEl!.textContent).toContain('Current');

let completedStep = stepListItems[0];
let completedIds = completedStep.getAttribute('aria-labelledby')!.split(' ');
let completedStateEl = document.getElementById(completedIds[1]);
expect(completedStateEl!.textContent).toContain('Completed');

let notCompletedStep = stepListItems[3];
let notCompletedIds = notCompletedStep.getAttribute('aria-labelledby')!.split(' ');
let notCompletedStateEl = document.getElementById(notCompletedIds[1]);
expect(notCompletedStateEl!.textContent).toContain('Not');
});

it('attaches a user provided ref', function () {
const ref = React.createRef<DOMRefValue<HTMLDivElement>>();
const container = renderComponent({ref});
Expand Down
Loading