Skip to content

Commit

Permalink
adds button loading state guidelines (#686)
Browse files Browse the repository at this point in the history
  • Loading branch information
mperrotti authored Dec 1, 2023
1 parent 89fa70a commit 3373d0c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 34 deletions.
54 changes: 54 additions & 0 deletions content/components/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,31 @@ There are two recommended ways an inactive button should respond to user input:

</Box>

### Loading

<Box
mb={3}
display="flex"
alignItems="flex-start"
justifyContent="space-between"
flexDirection={['column', 'column', 'column', 'column', 'row']}
sx={{gap: 3}}
>

<img
width="456"
alt="An button that looks disabled, but the text is replaced with a spinning loading indicator"
src="https://github.com/primer/design/assets/2313998/332baaba-6c0d-4d6c-b9cb-57616d35d9f2"
/>

<div>

You may use a button loading state if we need to wait for a button's action to be completed. Refer to the accessibility section's [button loading state](#button-loading-state) guidance for more information.

</div>

</Box>

## Best practices

### Primary and outline button usage
Expand Down Expand Up @@ -417,6 +442,35 @@ Labeling buttons properly lets users know what will happen when they activate th

Read more about [descriptive buttons](/guides/accessibility/descriptive-buttons).

### Button loading state

<img
width="960"
alt="A button in a loading state with a11y annotations"
src="https://github.com/primer/design/assets/2313998/87f87136-1414-4ae7-8e4b-1b4d6e6b2d20"
/>

<Box display="flex" flexDirection={['column', 'column', 'column', 'column', 'row']} sx={{alignItems: 'start', gap: 3, mt: 3, mb: 3}}>

<Box flex={1}>

When implementing a "loading" button state, don't remove the button from the DOM or pass the `disabled` attribute. Doing so would make it impossible to tab to the button. If the button was just focused and activated, it would reset focus. Resetting focus would disrupt the keyboard navigation flow, and creates a confusing experience for assistive technologies such as screen readers.

Once the button is activated (and is in a loading state), it get the attribute `aria-disabled="true"`.

A separate, visually hidden element should be rendered outside of the `<button>` with a message to communicate the loading status. For example, "Saving profile".

</Box>

<CustomVideoPlayer loop autoplay width="350" src="https://github.com/primer/design/assets/2313998/b138567f-3ba8-49ab-9fa1-80a4fe30b034" />

</Box>

This message should be in an ARIA live region, using `aria-live="polite"`. The live region must be present on page load, but the message inside the live region should only be rendered while the button is in a loading state.

If an error prevents process from being completed, focus should be brought to an `<h2>` (or next relevant heading) of the error banner.


### Known accessibility issues (GitHub staff only)

<AccessibilityLink label="Button"/>
37 changes: 3 additions & 34 deletions content/ui-patterns/loading.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -369,56 +369,25 @@ If the process loads new content, move focus to first focusable element in the n

You may disable form controls after the user submits the form to avoid confusion over whether changes that were made during the submission process will be saved.

However, the button that initiates the a loading process may not be semantically disabled.
However, the button that initiates the a loading process may not be semantically disabled using `aria-disabled`. For more information about button loading states, see the [loading section](/components/button#loading) of the button component guidelines.

</Box>

<CustomVideoPlayer
width="456"
loop
autoplay
src="https://github.com/primer/design/assets/2313998/cc592284-08d9-4330-8f36-548f27615706"
src="https://github.com/primer/design/assets/2313998/b138567f-3ba8-49ab-9fa1-80a4fe30b034"
/>
</Box>

### Button loading state

<>
{/*<!-- _TODO: Move most of the button loading state details to the [Button interface guidelines](/components/button) after we add the loading state to the "Options" section of those docs._ -->*/}
</>

<img
width="960"
alt="A button in a loading state with a11y annotations"
src="https://github.com/primer/design/assets/2313998/aa5303d6-04d0-44c7-bafe-438344c929b6"
/>

<Box display="flex" flexDirection={['column', 'column', 'column', 'column', 'row']} sx={{alignItems: 'start', gap: 3, marginTop: 3}}>

<Box flex={1}>

When implementing a "loading" button state, don't remove the button from the DOM or pass the `disabled` attribute. Doing so would make it impossible to tab to the button. If the button was just focused and activated, it would reset focus. Resetting focus would disrupt the keyboard navigation flow, and creates a confusing experience for assistive technologies such as screen readers.

Once the button is activated (and is in a loading state), it get the attribute `aria-disabled="true"`.

A separate, visually hidden element should be rendered outside of the `<button>` with a message to communicate the loading status. For example, "Saving profile".

</Box>

<CustomVideoPlayer loop autoplay width="456" src="https://github.com/primer/design/assets/2313998/ffaff3c9-5428-4d67-95e5-693a5f8880a4" />
</Box>

This message should be in an ARIA live region, using `aria-live="polite"`. The live region must be present on page load, but the message inside the live region should only be rendered while the button is in a loading state.

If an error prevents process from being completed, focus should be brought to an `<h2>` (or next relevant heading) of the error banner.

### Motion considerations

Animated loading indicators help reassure the user that the system isn't frozen, and should not be disabled when for users that prefer reduced motion. However, the animation in loading indicators should be kept as subtle as possible. Large, flashy animations would be harmful to users with sensitivity to motion.

## Related links

- [Graceful degradation](ui-patterns/degraded-experiences)
- [Graceful degradation](/ui-patterns/degraded-experiences)
- [Patterns for saving](/ui-patterns/saving)
- [Spinner](/components/spinner)
- [ProgressBar](/components/progress-bar)

0 comments on commit 3373d0c

Please sign in to comment.