Skip to content

Toggle switch component guidelines #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 30, 2022
Merged
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
9 changes: 9 additions & 0 deletions content/components/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ import {Grid, Flex, Box, Link, Text, Label} from '@primer/components'
<Link href="/design/components/autocomplete" fontWeight="bold">Autocomplete</Link>
<Box as="p">Autocomplete inputs allow users to quickly filter through a list of options to pick one or more values for a field.</Box>
</div>
<div>
<Link href="/design/components/toggle-switch">
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159758160-9d6b52ec-34f3-4fd8-b4ae-25b523dd3c0f.png" />
</Link>
</div>
<div>
<Link href="/design/components/toggle-switch" fontWeight="bold">Toggle switch</Link>
<Box as="p">A toggle switch is used to immediately toggle a setting on or off.</Box>
</div>
<div>
<Link href="/design/components/tokens">
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/138136341-c85ccaf9-f83f-4933-9fde-9a7b9c630fe4.png" />
Expand Down
145 changes: 145 additions & 0 deletions content/components/toggle-switch.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
title: Toggle switch
description: A toggle switch is used to immediately toggle a setting on or off.
---

import {Box, Text} from '@primer/components'

## Anatomy

![Diagram of toggle switch with its parts labeled](https://user-images.githubusercontent.com/2313998/159750870-0b575598-53f5-4215-9fb0-2ba078183dda.png)

- **Track**: The clickable area where the toggle switch moves back and forth
- **Knob**: Changes color and position depending on whether the switch is on or off
- **Status**: A text label showing whether the switch is on or off

## Options

### Label and description

<Box mb={5} display="flex" alignItems="flex-start" flexDirection={["column", "column", "column", "column", "row"]} sx={{gap: 3}}>
<div>
<Box as="p" mt="0">Every toggle switch should have a label that says what is being turned on or off. Optionally, you may include a description about the setting that is being turned on or off.</Box>
<Box as="p" mt="0">Labels should be succinct, and can describe an object or an action (for example: "Discussions" or "Automatically watch repositories"). Don't use phrases that describe the switch's state in your label.</Box>
</div>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159587115-5ffcdefb-f5e9-4180-8dc3-5328b0440f7f.png"
/>
</Box>

<DoDontContainer>
<Do>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587088-99e8fe4c-59a3-4452-836d-bd6f2297045a.png" />
<Caption>Use succinct phrases with verbs or nouns</Caption>
</Do>
<Dont>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587096-5f8a6913-df95-4ea0-9838-a366faf95e52.png" />
<Caption>Don't use phrases that describe the switch's state</Caption>
</Dont>
</DoDontContainer>

### Layout

<Box mb={3} display="flex" alignItems="flex-start" flexDirection={["column", "column", "column", "column", "row"]} sx={{gap: 3}}>
<div>
<Box as="p" mt="0">By default, lay out a toggle switch horizontally justified with its label and optional description.</Box>
<Box as="p" mt="0">You may use a vertical layout when a toggle switch is layed out inline with other content, or if a horizontal layout would put the switch too far from its label. If the vertical layout is left-aligned, the "on"/"off" text may be moved to the right of the switch.</Box>
</div>
<Box display="flex" flexDirection="column" sx={{gap: 2, flexGrow: 1, flexShrink: 0}}>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159587115-5ffcdefb-f5e9-4180-8dc3-5328b0440f7f.png"
/>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159587126-8d30ff26-33a8-4b84-87db-13dcfdff9dac.png"
/>
</Box>
</Box>

### Size

<Box mb={3} display="flex" alignItems="flex-start" flexDirection={["column", "column", "column", "column", "row"]} sx={{gap: 3}}>
<Box as="p" mt="0">A small variant is provided to maintain visual hierarchy, or for dense areas where the default size will not fit.</Box>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159587124-e7ef0a16-fd42-4614-be3e-80c985332ef7.png"
/>
</Box>

### Loading

<Box mb={3} display="flex" alignItems="flex-start" flexDirection={["column", "column", "column", "column", "row"]} sx={{gap: 3}}>
<Box as="p" mt="0">When a toggle switch is waiting for something to load before toggling, a loading indicator should be displayed. The switch should not prematurely toggle from "on" to "off". Wait until loading is complete before showing a change.</Box>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159587116-aa07a847-a633-4515-82b3-20ebe2349914.png"
/>
</Box>

### Progressive disclosure

<Box mb={3} display="flex" alignItems="flex-start" flexDirection={["column", "column", "column", "column", "row"]} sx={{gap: 3}}>
<Box as="p" mt="0">The <a href="/ui-patterns/progressive-disclosure">progressive disclosure pattern</a> may be used to hide or show content based on whether a toggle switch is on. Content revealed on toggle switch activation should always come <em>after</em> the toggle switch.</Box>
<img
width="456"
role="presentation"
src="https://user-images.githubusercontent.com/2313998/159591632-f604ec1d-aca9-42f7-ad65-16f8811f192f.png"
/>
</Box>

## Accessibility

### Keyboard navigation

Toggle switches should have the same keyboard navigation features as a button. A toggle switch may be focused using the `Tab` key, and pressing the `Enter` or `Space` key will toggle the switch.

### Touch target

When the UI is rendered on a touch-screen device, ensure that the toggle switch has a large enough touch target size. The toggle switch should respond to hovers, clicks, and taps anywhere in the touch target area, even if it isn't directly on the control.

![Diagram showing touch target size on medium and small toggle switches](https://user-images.githubusercontent.com/2313998/159587125-7b4c5f1a-2cdb-4653-8650-6c94d78e951d.png)

## Mixed values

Since a toggle switch can only be "on" or "off", it could be confusing to use a switch to represent mixed values.

If you have a group of configuration options that can be disabled, use a button instead of a toggle switch. Disabling the group turns off all configuration options, but remembers their previous state when the user wants to turn that section back on. While the section is disabled, the configuration options are hidden.

![Configuration options section that can be enabled or disabled. Configuration controls are hidden when it is disabled.](https://user-images.githubusercontent.com/2313998/159587120-2d842830-18c7-4429-bd10-f5424f6fac9e.png)


<DoDontContainer>
<Do>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587100-1a1af5b2-dd19-456a-a0ed-c2f9fa7f7c2e.png" />
<Caption>Use a button to affect multiple related toggles</Caption>
</Do>
<Dont>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587101-446548c2-41c3-45c1-b710-db3149e2ebe4.png" />
<Caption>Don't use a toggle switch to represent mixed values</Caption>
</Dont>
</DoDontContainer>

## Toggle switch vs checkbox

Toggle switches are buttons that change and save a boolean configuration option when they are toggled.
Checkboxes are form inputs that are used to select one or more items from a list, and are not saved without explicit confirmation such as pressing a **Save** button.

A toggle switch should never be used as a replacement for a checkbox. See [saving patterns](/ui-patterns/saving) for more details.

<DoDontContainer>
<Do>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587105-45d50974-eb76-46cd-a3fd-c1e0f605f3ef.png" />
<Caption>Use a toggle switch like a button</Caption>
</Do>
<Dont>
<img role="presentation" src="https://user-images.githubusercontent.com/2313998/159587113-6c8461f7-3d4d-4e6a-b3a5-c585c5143fba.png" />
<Caption>Don't use a toggle switch as a replacement for a checkbox</Caption>
</Dont>
</DoDontContainer>
21 changes: 14 additions & 7 deletions content/ui-patterns/saving.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ If there is an error saving the data, the user's data should be preserved in the

<DoDontContainer>
<Do>
<img alt="A form broken into two sections where one section has a dropdown that automatically saves" src="https://user-images.githubusercontent.com/2313998/151887935-980adacd-41aa-47cb-8756-eeaa1a6d0f2b.png" />
<img alt="A form broken into two sections where one section has a dropdown that automatically saves" src="https://user-images.githubusercontent.com/2313998/159594852-aa1223c7-201e-42ea-9109-649371709d22.png" />
<Caption>Separate auto-saving controls from an explicitly saved form</Caption>
</Do>
<Dont>
<img alt="A form with a single section and it contains a dropdown that automatically saves" src="https://user-images.githubusercontent.com/2313998/151887936-d41900ca-2d63-43ac-bf82-55b4bba0df61.png" />
<img alt="A form with a single section and it contains a dropdown that automatically saves" src="https://user-images.githubusercontent.com/2313998/159594854-8edb9736-bdd1-436c-a327-8525b6ddac0c.png" />
<Caption>Don't mix auto-saving controls and explicitly saved controls in the same form</Caption>
</Dont>
</DoDontContainer>
Expand Down Expand Up @@ -52,6 +52,14 @@ To ensure your forms are accessible, you should use explicit saving (and not aut
</Dont>
</DoDontContainer>

There are a few issues to bear in mind with autosaving declarative controls.

- Text inputs: Users expect to set a value and then submit. Sensitive information could be unintentionally submitted, such as a change password input.
- Checkbox groups: It could be unclear whether or not the selection has been saved. Users may accidentally submit a selection clicked by accident.
- Radio button groups: Screenreader users can't read the options without selecting them, which could accidentally apply a selection the user didn't want.
- Browser-native `<select>` dropdowns: Similarly to radio button groups, options could be selected when a user focuses the select and uses the arrow keys to read through each option.


### Calls to action

When data is not automatically saved after the user makes changes, buttons are used to submit or cancel the changes.
Expand Down Expand Up @@ -216,12 +224,11 @@ Automatic saving applies changes as they are made. Automatic saving should be us
<Text as="p" mt="0" align="center" fontSize={1}>If a form field is saved automatically, it should be obvious whether or not it saved without using text or visual indicators. A visual indicator for whether or not a form field has been saved successfully could be mistaken as a validation status.</Text>
</Box>

There are a few issues to bear in mind with autosaving [declarative controls](#declarative-controls).
### Imperative controls

- Text inputs: Users expect to set a value and then submit. Sensitive information could be unintentionally submitted, such as a change password input.
- Checkbox groups: It could be unclear whether or not the selection has been saved. Users may accidentally submit a selection clicked by accident.
- Radio button groups: Screenreader users can't read the options without selecting them, which could accidentally apply a selection the user didn't want.
- Browser-native `<select>` dropdowns: Similarly to radio button groups, options could be selected when a user focuses the select and uses the arrow keys to read through each option.
To reduce UI and give instant feedback, you should use automatic saving (and not explicit saving) for imperative controls. These are:
- [Toggle switches](/components/toggle-switch). The toggle switch behaves like a light switch: the light just switches on and off without you having to confirm each time you flip the switch.
- Single-select dropdowns that are not native `<select>` dropdowns or part of an explicitly saved form. Single-select dropdowns behave like a radio dial: the station starts playing as soon as you select it.

### Dropdown menu accessibility

Expand Down
2 changes: 2 additions & 0 deletions src/@primer/gatsby-theme-doctocat/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
url: /components/action-list
- title: Autocomplete
url: /components/autocomplete
- title: Toggle switch
url: /components/toggle-switch
- title: Tokens
url: /components/tokens
- title: Design tools
Expand Down