Skip to content

Commit

Permalink
fix: Focus element with accessible role when switching steps (#3235)
Browse files Browse the repository at this point in the history
Co-authored-by: Johannes Weber <[email protected]>
  • Loading branch information
johannes-weber and Johannes Weber authored Feb 4, 2025
1 parent 3146174 commit 0451d85
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
30 changes: 30 additions & 0 deletions src/header/__tests__/internal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { render } from '@testing-library/react';

import InternalHeader from '../../../lib/components/header/internal';
import createWrapper from '../../../lib/components/test-utils/dom';

describe('InternalHeader', () => {
test('tabindex attribute is not set when not provided', () => {
render(<InternalHeader variant="h3">h3 title</InternalHeader>);
const headerElement = createWrapper().find('h3')!.getElement();
expect(headerElement).not.toHaveAttribute('tabindex');
});

test('heading tag is focusable via ref', () => {
const ref = React.createRef<HTMLHeadingElement>();
render(
<InternalHeader variant="h3" __headingTagTabIndex={-1} __headingTagRef={ref}>
h3 title
</InternalHeader>
);
const headerElement = createWrapper().find('h3')!.getElement();
expect(headerElement).toHaveTextContent('h3 title');
expect(headerElement).toHaveAttribute('tabindex', '-1');
expect(document.activeElement).not.toBe(headerElement);
ref.current?.focus();
expect(document.activeElement).toBe(headerElement);
});
});
8 changes: 7 additions & 1 deletion src/header/internal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useContext } from 'react';
import React, { MutableRefObject, useContext } from 'react';
import clsx from 'clsx';

import { getAnalyticsLabelAttribute } from '@cloudscape-design/component-toolkit/internal/analytics-metadata';
Expand All @@ -23,6 +23,8 @@ import styles from './styles.css.js';

interface InternalHeaderProps extends SomeRequired<HeaderProps, 'variant'>, InternalBaseComponentProps {
__disableActionsWrapping?: boolean;
__headingTagRef?: MutableRefObject<HTMLHeadingElement | null>;
__headingTagTabIndex?: number;
}

export default function InternalHeader({
Expand All @@ -35,6 +37,8 @@ export default function InternalHeader({
info,
__internalRootRef = null,
__disableActionsWrapping,
__headingTagRef,
__headingTagTabIndex,
...restProps
}: InternalHeaderProps) {
const isMobile = useMobile();
Expand Down Expand Up @@ -76,6 +80,8 @@ export default function InternalHeader({
<div className={clsx(styles.title, styles[`title-variant-${variantOverride}`], isRefresh && styles.refresh)}>
<HeadingTag
className={clsx(styles.heading, styles[`heading-variant-${variantOverride}`])}
ref={__headingTagRef}
tabIndex={__headingTagTabIndex}
{...getAnalyticsLabelAttribute(`.${analyticsSelectors['heading-text']}`)}
>
<span
Expand Down
11 changes: 9 additions & 2 deletions src/wizard/wizard-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,15 @@ function WizardForm({
<div className={clsx(styles['collapsed-steps'], !showCollapsedSteps && styles['collapsed-steps-hidden'])}>
{i18nStrings.collapsedStepsLabel?.(activeStepIndex + 1, steps.length)}
</div>
<InternalHeader className={styles['form-header-component']} variant="h1" description={description} info={info}>
<span className={styles['form-header-component-wrapper']} tabIndex={-1} ref={stepHeaderRef}>
<InternalHeader
className={styles['form-header-component']}
variant="h1"
description={description}
info={info}
__headingTagRef={stepHeaderRef}
__headingTagTabIndex={-1}
>
<span className={styles['form-header-component-wrapper']}>
<span {...{ [DATA_ATTR_FUNNEL_KEY]: FUNNEL_KEY_STEP_NAME }}>{title}</span>
{isOptional && <i>{` - ${i18nStrings.optional}`}</i>}
</span>
Expand Down

0 comments on commit 0451d85

Please sign in to comment.