Skip to content
Draft
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
11 changes: 9 additions & 2 deletions packages/react/src/Button/Button.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@
{
"id": "components-button-features--loading-trigger"
},
{
"id": "components-button-examples--loading-status-announcement-successful"
},
{
"id": "components-button-examples--loading-status-announcement-error"
},
{
"id": "components-button-features--label-wrap"
},
Expand Down Expand Up @@ -135,12 +141,13 @@
{
"name": "loading",
"type": "boolean",
"description": "When true, the button is in a loading state."
"description": "When true, the button is in a loading state. A spinner replaces the button's content and the button automatically announces its loading state to screen readers through a built-in, visually hidden live region. Do not add your own separate `aria-live` loading message for the button, as that would cause a duplicate announcement."
},
{
"name": "loadingAnnouncement",
"type": "string",
"description": "The content to announce to screen readers when loading. This requires `loading` prop to be true"
"defaultValue": "'Loading'",
"description": "The text announced to screen readers through the built-in, visually hidden live region when the button enters its loading state. Requires the `loading` prop to be true."
},
{
"name": "ref",
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/Button/Button.examples.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ export const LoadingStatusAnnouncementSuccessful = () => {
</>
)
}
LoadingStatusAnnouncementSuccessful.parameters = {
docs: {
description: {
story:
'While `loading` is set, the button announces its loading state for you through its built-in live region, so you should not add a separate loading announcement. Announcing the *result* of the action is still your responsibility — here, a polite `AriaStatus` live region announces "Export completed" once the action resolves successfully.',
},
},
}

export const LoadingStatusAnnouncementError = () => {
const [loading, setLoading] = React.useState(false)
Expand Down Expand Up @@ -81,3 +89,11 @@ export const LoadingStatusAnnouncementError = () => {
</>
)
}
LoadingStatusAnnouncementError.parameters = {
docs: {
description: {
story:
'The button handles the loading announcement for you, so you only need to announce the outcome. Here, an assertive `AriaAlert` surfaces an error `Banner` when the action fails.',
},
},
}
16 changes: 16 additions & 0 deletions packages/react/src/Button/Button.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,28 @@ export const Medium = () => <Button size="medium">Default</Button>
export const Large = () => <Button size="large">Default</Button>

export const Loading = () => <Button loading>Default</Button>
Loading.parameters = {
docs: {
description: {
story:
'When `loading` is set, the button automatically renders a visually hidden live region that announces "Loading" to screen readers. Because this announcement is built in, do not add your own separate `aria-live` loading message for the button — doing so would cause a duplicate announcement.',
},
},
}

export const LoadingCustomAnnouncement = () => (
<Button loading loadingAnnouncement="This is a custom loading announcement">
Default
</Button>
)
LoadingCustomAnnouncement.parameters = {
docs: {
description: {
story:
'Use the `loadingAnnouncement` prop to customize the text announced to screen readers when the button enters its loading state. This replaces the default "Loading" announcement.',
},
},
}

export const LoadingWithLeadingVisual = () => (
<Button loading leadingVisual={DownloadIcon}>
Expand Down
11 changes: 11 additions & 0 deletions packages/react/src/Button/IconButton.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@
"defaultValue": "",
"description": "Changes the size of the icon button component"
},
{
"name": "loading",
"type": "boolean",
"description": "When true, the button is in a loading state. A spinner replaces the icon and the button automatically announces its loading state to screen readers through a built-in, visually hidden live region. Do not add your own separate `aria-live` loading message for the button, as that would cause a duplicate announcement."
},
{
"name": "loadingAnnouncement",
"type": "string",
"defaultValue": "'Loading'",
"description": "The text announced to screen readers through the built-in, visually hidden live region when the button enters its loading state. Requires the `loading` prop to be true."
},
{
"name": "inactive",
"type": "boolean",
Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/Button/IconButton.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export const AsAMenuAnchor = () => (
)

export const Loading = () => <IconButton loading icon={HeartIcon} variant="primary" aria-label="Primary" />
Loading.parameters = {
docs: {
description: {
story:
'When `loading` is set, the button automatically renders a visually hidden live region that announces "Loading" to screen readers. Customize this text with the `loadingAnnouncement` prop. Because the announcement is built in, do not add your own separate `aria-live` loading message for the button — doing so would cause a duplicate announcement.',
},
},
}

export const LoadingTrigger = () => {
const [isLoading, setIsLoading] = useState(false)
Expand Down
9 changes: 7 additions & 2 deletions packages/react/src/Button/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,16 @@ export type ButtonBaseProps = {
*/
block?: boolean
/**
* Specify whether the button is in a loading state
* Specify whether the button is in a loading state. While loading, a spinner replaces the
* button's content and the button automatically announces its loading state to screen readers
* through a visually hidden live region. Do not add a separate `aria-live` loading message for
* the button, as that would cause a duplicate announcement.
*/
loading?: boolean
/**
* The content to announce to screen readers when loading
* The text announced to screen readers through the built-in visually hidden live region when the
* button enters its loading state. Requires `loading` to be true.
* @default 'Loading'
*/
loadingAnnouncement?: string
/*
Expand Down
Loading