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
3 changes: 3 additions & 0 deletions packages/eui/changelogs/upcoming/9574.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Accessibility**

- Fixed duplicate screen reader output for `EuiStepsHorizontal`
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ exports[`EuiStepHorizontal is rendered 1`] = `
class="euiStepHorizontal testClass1 testClass2 emotion-euiStepHorizontal-enabled-euiTestCss"
data-step-status="incomplete"
data-test-subj="test subject string"
title="Step 1 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand All @@ -31,9 +30,9 @@ exports[`EuiStepHorizontal is rendered 1`] = `

exports[`EuiStepHorizontal props size m is rendered 1`] = `
<button
aria-label="Step 1 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 1 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand All @@ -58,9 +57,9 @@ exports[`EuiStepHorizontal props size m is rendered 1`] = `

exports[`EuiStepHorizontal props size s is rendered 1`] = `
<button
aria-label="Step 1 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 1 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-xs-incomplete-euiStepHorizontal__number"
Expand All @@ -85,9 +84,9 @@ exports[`EuiStepHorizontal props size s is rendered 1`] = `

exports[`EuiStepHorizontal props size xs is rendered 1`] = `
<button
aria-label="Step 1 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 1 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-none-incomplete-euiStepHorizontal__number"
Expand All @@ -106,9 +105,9 @@ exports[`EuiStepHorizontal props size xs is rendered 1`] = `

exports[`EuiStepHorizontal props status complete is rendered 1`] = `
<button
aria-label="Step 1 is complete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="complete"
title="Step 1 is complete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-complete-euiStepHorizontal__number"
Expand All @@ -128,9 +127,9 @@ exports[`EuiStepHorizontal props status complete is rendered 1`] = `

exports[`EuiStepHorizontal props status current is rendered 1`] = `
<button
aria-label="Current step is 1"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="current"
title="Current step is 1"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-current-euiStepHorizontal__number"
Expand All @@ -155,9 +154,9 @@ exports[`EuiStepHorizontal props status current is rendered 1`] = `

exports[`EuiStepHorizontal props status danger is rendered 1`] = `
<button
aria-label="Step 1 has errors"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="danger"
title="Step 1 has errors"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-danger-euiStepHorizontal__number"
Expand All @@ -178,9 +177,9 @@ exports[`EuiStepHorizontal props status danger is rendered 1`] = `
exports[`EuiStepHorizontal props status disabled is rendered 1`] = `
<button
aria-disabled="true"
aria-label="Step 1 is disabled"
class="euiStepHorizontal emotion-euiStepHorizontal-disabled"
data-step-status="disabled"
title="Step 1 is disabled"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-disabled-euiStepHorizontal__number"
Expand All @@ -206,10 +205,10 @@ exports[`EuiStepHorizontal props status disabled is rendered 1`] = `
exports[`EuiStepHorizontal props status disabled overrides the passed status 1`] = `
<button
aria-disabled="true"
aria-label="Step 1 is disabled"
class="euiStepHorizontal emotion-euiStepHorizontal-disabled"
data-step-status="disabled"
disabled=""
title="Step 1 is disabled"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-disabled-euiStepHorizontal__number"
Expand All @@ -234,9 +233,9 @@ exports[`EuiStepHorizontal props status disabled overrides the passed status 1`]

exports[`EuiStepHorizontal props status incomplete is rendered 1`] = `
<button
aria-label="Step 1 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 1 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand All @@ -261,9 +260,9 @@ exports[`EuiStepHorizontal props status incomplete is rendered 1`] = `

exports[`EuiStepHorizontal props status loading is rendered 1`] = `
<button
aria-label="Step 1 is loading"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="loading"
title="Step 1 is loading"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-loading-euiStepHorizontal__number"
Expand All @@ -287,9 +286,9 @@ exports[`EuiStepHorizontal props status loading is rendered 1`] = `

exports[`EuiStepHorizontal props status warning is rendered 1`] = `
<button
aria-label="Step 1 has warnings"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="warning"
title="Step 1 has warnings"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-warning-euiStepHorizontal__number"
Expand All @@ -309,9 +308,9 @@ exports[`EuiStepHorizontal props status warning is rendered 1`] = `

exports[`EuiStepHorizontal props step 1`] = `
<button
aria-label="Step 5 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 5 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand All @@ -336,9 +335,9 @@ exports[`EuiStepHorizontal props step 1`] = `

exports[`EuiStepHorizontal props title 1`] = `
<button
aria-label="Step 1: First step is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 1: First step is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ exports[`EuiStepsHorizontal is rendered 1`] = `
class="euiStepsHorizontal__item emotion-euiStepsHorizontal__item"
>
<button
aria-label="Step 1: Completed Step 1 is complete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="complete"
title="Step 1: Completed Step 1 is complete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-complete-euiStepHorizontal__number"
Expand All @@ -36,9 +36,9 @@ exports[`EuiStepsHorizontal is rendered 1`] = `
class="euiStepsHorizontal__item emotion-euiStepsHorizontal__item"
>
<button
aria-label="Current step 2: Selected Step 2"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="current"
title="Current step 2: Selected Step 2"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-current-euiStepHorizontal__number"
Expand Down Expand Up @@ -66,9 +66,9 @@ exports[`EuiStepsHorizontal is rendered 1`] = `
class="euiStepsHorizontal__item emotion-euiStepsHorizontal__item"
>
<button
aria-label="Step 3: Incomplete Step 3 is incomplete"
class="euiStepHorizontal emotion-euiStepHorizontal-enabled"
data-step-status="incomplete"
title="Step 3: Incomplete Step 3 is incomplete"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-incomplete-euiStepHorizontal__number"
Expand Down Expand Up @@ -97,9 +97,9 @@ exports[`EuiStepsHorizontal is rendered 1`] = `
>
<button
aria-disabled="true"
aria-label="Step 4: Disabled Step 4 is disabled"
class="euiStepHorizontal emotion-euiStepHorizontal-disabled"
data-step-status="disabled"
title="Step 4: Disabled Step 4 is disabled"
>
<span
class="euiStepNumber euiStepHorizontal__number emotion-euiStepNumber-m-disabled-euiStepHorizontal__number"
Expand Down
11 changes: 7 additions & 4 deletions packages/eui/src/components/steps/step_horizontal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const EuiStepHorizontal: FunctionComponent<EuiStepHorizontalProps> = ({
disabled,
status = 'incomplete',
size = 'm',
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
...rest
}) => {
if (disabled) status = 'disabled';
Expand All @@ -96,7 +98,7 @@ export const EuiStepHorizontal: FunctionComponent<EuiStepHorizontalProps> = ({
status === 'disabled' && titleStyles.disabled,
];

const titleAttrsMap: Record<EuiStepStatus | 'step', string> = {
const labelMap: Record<EuiStepStatus | 'step', string> = {
step: useI18nStep({ number: step, title }),
current: useI18nCurrentStep({ number: step, title }),
disabled: useI18nDisabledStep({ number: step, title }),
Expand All @@ -106,19 +108,20 @@ export const EuiStepHorizontal: FunctionComponent<EuiStepHorizontalProps> = ({
danger: useI18nErrorsStep({ number: step, title }),
loading: useI18nLoadingStep({ number: step, title }),
};
const titleAttr = titleAttrsMap[status || 'step'];
const ariaLabelAttr = labelMap[status || 'step'];

const onStepClick = (
event: ReactMouseEvent<HTMLButtonElement, MouseEvent>
) => {
if (!disabled) onClick(event);
if (!disabled && status !== 'disabled') onClick(event);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Before, when using status === 'disabled' onClick would still be triggered which does not make sense but is a behavioral change that we didn't mention in the PR description/changelog, and can potentially break some cases if they rely on it? 🤔

};

return (
<button
aria-disabled={status === 'disabled' ? true : undefined}
className={classes}
title={titleAttr}
aria-label={ariaLabel ?? (ariaLabelledby ? undefined : ariaLabelAttr)}
aria-labelledby={ariaLabelledby}
onClick={onStepClick}
disabled={disabled}
Comment on lines 121 to 126
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

aria-disabled is set based on status === 'disabled', but the actual disabled behavior is controlled only by the disabled prop (disabled={disabled} and onStepClick only guards on disabled). This allows a status="disabled" step to still be clickable/activatable despite being announced as disabled. Consider using a single computed boolean (e.g., isDisabled = disabled || status === 'disabled') for aria-disabled, the disabled attribute, and the click guard so behavior matches the a11y state.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's not due to the changes in this PR. There might be benefit to having the button focusable if disabled, so I wouldn't change the aria-disabled vs disabled behavior here at this point. What we can do though is guard the onClick on both to prevent it from being being fired if only status === 'disabled' is passed without disabled.

Updated in 0fa990a

css={cssStyles}
Expand Down