Command
A search-first menu of actions and places, opened from the keyboard.
Left out of Accessible first Command is for expert users who jump anywhere by typing. Here people do this once or twice a year and nobody remembers the interface. Use instead: Button
See it live
npm run storybookWhen to use it
- Use it when: Expert users who want to jump anywhere or run any action by typing.
- Not when: The only way to reach an action, or people who visit now and then.
Instead:
- Dropdown menu: A short menu from a button.
- Combobox: Picking a value for a field.
Words
- Use common words. Explain any term you must use.
- One idea per sentence. Put the action first.
- Never blame the person.
- Use: Continue, Change, Start, You. Avoid: Invalid, Utilise, Submit, Error code.
The labels components use, from the voice tokens:
content.action.commit: Continuecontent.action.cancel: Go backcontent.action.destroy: Deletecontent.action.retry: Try againcontent.action.empty-action: Start a new application
See Voice and tone for the whole voice.
Accessibility and keyboard
| Keyboard | What happens | Not |
|---|---|---|
| undefined | A shortcut opens it; arrows move; Enter runs; Escape closes. | undefined |
Test before you ship:
- Results are a list; the active result is announced. undefined
Use it in code
npx open-ds add command
The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.
Tokens it reads
Command reads 38 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Command's tokens to change Command alone.
Accessible first decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.
| Part | Its token and the semantic it aliases | Value |
|---|---|---|
| Command | ||
| Corner | component.command.radiusradius.controlvar(--command-radius) | radius.6:0.375rem |
| Fill Changes with theme | component.command.backgroundcolor.surface.raisedvar(--command-background) | Lightgray.light.0:#FFFFFFDarkgray.dark.100:#222222 |
| Text Changes with theme | component.command.labelcolor.text.primaryvar(--command-label) | Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7 |
| Padding, left and right | component.command.padding-xcomponent-spacing-map.x2var(--command-padding-x) | space.8:0.5rem |
| Weight | component.command.font-weighttype.label.font-weightvar(--command-font-weight) | font.weight.700:700 |
| Label 2 Changes with theme | component.command.label-2color.text.mutedvar(--command-label-2) | Lightgray.light.500:#595959Darkgray.dark.500:#949494 |
| Padding, top and bottom | component.command.padding-ycomponent-spacing-map.x3var(--command-padding-y) | space.20:1.25rem |
| Icon size | component.command.icon-sizesize.iconvar(--command-icon-size) | size.20:1.25rem |
| Disabled opacity | component.command.disabled-opacityopacity.disabledvar(--command-disabled-opacity) | opacity.50:0.5 |
| Input | ||
| Wrapper gap | component.command.input.wrapper.gapspace.gap.defaultvar(--command-input-wrapper-gap) | space.16:1rem |
| Wrapper padding x | component.command.input.wrapper.padding-xcomponent-spacing-map.x3var(--command-input-wrapper-padding-x) | space.20:1.25rem |
| Corner | component.command.input.radiusradius.controlvar(--command-input-radius) | radius.6:0.375rem |
| Padding, top and bottom | component.command.input.padding-ycomponent-spacing-map.x3var(--command-input-padding-y) | space.20:1.25rem |
| Text size | component.command.input.font-sizetype.body.font-sizevar(--command-input-font-size) | font.size.19:1.1875rem |
| Label placeholder Changes with theme | component.command.input.label-placeholdercolor.text.mutedvar(--command-input-label-placeholder) | Lightgray.light.500:#595959Darkgray.dark.500:#949494 |
| Disabled opacity disabled when disabled | component.command.input.disabled-opacity-disabledopacity.disabledvar(--command-input-disabled-opacity-disabled) | opacity.50:0.5 |
| Empty | ||
| Padding, top and bottom | component.command.empty.padding-ycomponent-spacing-map.x6var(--command-empty-padding-y) | space.44:2.75rem |
| Text size | component.command.empty.font-sizetype.body.font-sizevar(--command-empty-font-size) | font.size.19:1.1875rem |
| Group | ||
| Padding | component.command.group.paddingcomponent-spacing-map.x1var(--command-group-padding) | space.4:0.25rem |
| Text Changes with theme | component.command.group.labelcolor.text.primaryvar(--command-group-label) | Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7 |
| Padding, left and right | component.command.group.padding-xcomponent-spacing-map.x2var(--command-group-padding-x) | space.8:0.5rem |
| Padding, top and bottom | component.command.group.padding-ycomponent-spacing-map.x2var(--command-group-padding-y) | space.8:0.5rem |
| Text size | component.command.group.font-sizetype.caption.font-sizevar(--command-group-font-size) | font.size.16:1rem |
| Weight | component.command.group.font-weighttype.label.font-weightvar(--command-group-font-weight) | font.weight.700:700 |
| Label 2 Changes with theme | component.command.group.label-2color.text.mutedvar(--command-group-label-2) | Lightgray.light.500:#595959Darkgray.dark.500:#949494 |
| Separator | ||
| Fill Changes with theme | component.command.separator.backgroundcolor.border.defaultvar(--command-separator-background) | Lightgray.light.200:#D6D6D6Darkgray.dark.100:#222222 |
| Item | ||
| Gap | component.command.item.gapspace.gap.defaultvar(--command-item-gap) | space.16:1rem |
| Corner | component.command.item.radiusradius.badgevar(--command-item-radius) | radius.4:0.25rem |
| Padding, left and right | component.command.item.padding-xcomponent-spacing-map.x2var(--command-item-padding-x) | space.8:0.5rem |
| Padding, top and bottom | component.command.item.padding-ycomponent-spacing-map.x2var(--command-item-padding-y) | space.8:0.5rem |
| Text size | component.command.item.font-sizetype.body.font-sizevar(--command-item-font-size) | font.size.19:1.1875rem |
| Disabled opacity disabled when disabled | component.command.item.disabled-opacity-disabledopacity.disabledvar(--command-item-disabled-opacity-disabled) | opacity.50:0.5 |
| Background selected Changes with theme when selected | component.command.item.background-selectedcolor.surface.sunkenvar(--command-item-background-selected) | Lightgray.light.100:#EDEDEDDarkgray.dark.100:#222222 |
| Label selected Changes with theme when selected | component.command.item.label-selectedcolor.text.primaryvar(--command-item-label-selected) | Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7 |
| Icon size | component.command.item.icon-sizesize.iconvar(--command-item-icon-size) | size.20:1.25rem |
| Text Changes with theme | component.command.item.labelcolor.text.mutedvar(--command-item-label) | Lightgray.light.500:#595959Darkgray.dark.500:#949494 |
| Shortcut | ||
| Text size | component.command.shortcut.font-sizetype.caption.font-sizevar(--command-shortcut-font-size) | font.size.16:1rem |
| Text Changes with theme | component.command.shortcut.labelcolor.text.mutedvar(--command-shortcut-label) | Lightgray.light.500:#595959Darkgray.dark.500:#949494 |
| From the system | ||
| Edge Changes with theme | color.border.default straight from the system, through --border | Lightgray.light.200 · #D6D6D6Darkgray.dark.100 · #222222 |