Skip to content

Commit 0cf08f3

Browse files
authored
fix(Spinner): use aria-label when defined, falling back to srText (#4685)
* fix(Spinner): use aria-label when defined, falling back to srText * test(Spinner): add tests for aria-label support * docs: update Spinner API docs * chore: fix eslint warnings --------- Co-authored-by: Josh Black <[email protected]>
1 parent e957fef commit 0cf08f3

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

packages/react/src/Spinner/Spinner.docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
{
2121
"name": "aria-label",
22-
"type": "string | null",
22+
"type": "string",
2323
"description": "Sets the text conveyed by assistive technologies such as screen readers.",
2424
"deprecated": true
2525
},

packages/react/src/Spinner/Spinner.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ export type SpinnerProps = {
1818
/** Sets the text conveyed by assistive technologies such as screen readers. Set to `null` if the loading state is displayed in a text node somewhere else on the page. */
1919
srText?: string | null
2020
/** @deprecated Use `srText` instead. */
21-
'aria-label'?: string | null
21+
'aria-label'?: string
2222
} & HTMLDataAttributes &
2323
SxProp
2424

2525
function Spinner({size: sizeKey = 'medium', srText = 'Loading', 'aria-label': ariaLabel, ...props}: SpinnerProps) {
2626
const size = sizeMap[sizeKey]
27-
const hasSrAnnouncement = Boolean(srText || ariaLabel)
28-
const ariaLabelId = useId()
27+
const hasHiddenLabel = srText !== null && ariaLabel === undefined
28+
const labelId = useId()
2929

3030
return (
3131
/* inline-flex removes the extra line height */
@@ -36,7 +36,8 @@ function Spinner({size: sizeKey = 'medium', srText = 'Loading', 'aria-label': ar
3636
viewBox="0 0 16 16"
3737
fill="none"
3838
aria-hidden
39-
aria-labelledby={ariaLabelId}
39+
aria-label={ariaLabel ?? undefined}
40+
aria-labelledby={hasHiddenLabel ? labelId : undefined}
4041
{...props}
4142
>
4243
<circle
@@ -56,7 +57,7 @@ function Spinner({size: sizeKey = 'medium', srText = 'Loading', 'aria-label': ar
5657
vectorEffect="non-scaling-stroke"
5758
/>
5859
</svg>
59-
{hasSrAnnouncement ? <VisuallyHidden id={ariaLabelId}>{srText || ariaLabel}</VisuallyHidden> : null}
60+
{hasHiddenLabel ? <VisuallyHidden id={labelId}>{srText}</VisuallyHidden> : null}
6061
</Box>
6162
)
6263
}

packages/react/src/__tests__/Spinner.test.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import axe from 'axe-core'
33
import type {SpinnerProps} from '..'
44
import {Spinner} from '..'
55
import {behavesAsComponent, checkExports} from '../utils/testing'
6-
import {render as HTMLRender} from '@testing-library/react'
6+
import {render as HTMLRender, screen} from '@testing-library/react'
77

88
describe('Spinner', () => {
99
behavesAsComponent({
@@ -26,12 +26,17 @@ describe('Spinner', () => {
2626
expect(getByLabelText('Custom loading text')).toBeInTheDocument()
2727
})
2828

29-
it('should not label the spinner with with loading text when `srText` is set to `null`', async () => {
29+
it('should not label the spinner with with loading text when `srText` is set to `null`', () => {
3030
const {getByLabelText} = HTMLRender(<Spinner srText={null} />)
3131

3232
expect(() => getByLabelText('Loading')).toThrow()
3333
})
3434

35+
it('should use `aria-label` over `srText` if `aria-label` is provided', () => {
36+
HTMLRender(<Spinner aria-label="Test label" />)
37+
expect(screen.getByLabelText('Test label')).toBeInTheDocument()
38+
})
39+
3540
it('should have no axe violations', async () => {
3641
const {container} = HTMLRender(<Spinner />)
3742
const results = await axe.run(container)

0 commit comments

Comments
 (0)