On this page
Import
import { Button } from '@envsemble/envui';
Usage
<Button onClick={save}>Save</Button>
<Button variant="secondary">Cancel</Button>
<Button tone="danger">Delete project</Button>
<Button href="/projects">Open projects</Button>
<Button startIcon={<IconAdd />}>Create project</Button>
<Button pending={saving} onClick={save}>Save changes</Button>
A button without a variant or a size takes its container's, such as ghost in a Toolbar and sm in a table cell. With href it renders the router link from LinkProvider.
Icon only
import { IconButton } from '@envsemble/envui';
<IconButton icon={<IconSettings />} aria-label="Project settings" />;
An IconButton takes its container's variant too, and is otherwise secondary.
Confirm and copy
import { ConfirmButton, CopyButton } from '@envsemble/envui';
<ConfirmButton confirmLabel="Remove Sam" onConfirm={() => remove('sam')}>
Remove
</ConfirmButton>
<CopyButton value={shareLink} aria-label="Copy link" />
ConfirmButton with icon and an aria-label is icon-only until armed. When the confirmed action removes the button, move focus to what takes its place, as the ConfirmInPlace example does. CopyButton's write copies through a clipboard of the application's own.
Composition
import { ButtonGroup } from '@envsemble/envui';
<ButtonGroup aria-label="Project actions">
<Button>Open</Button>
<Button>Edit</Button>
</ButtonGroup>;
orientation="vertical" stacks a group, every button as wide as it; fullWidth makes a button or a group fill its container. end holds quiet content after the label, at the far end of a wide button, such as the Kbd of a shortcut, as the button that opens a CommandPalette does.
The label's parts are flex items the button's gap spaces apart, such as its words and a Badge. Words with an AnimatedNumber or an inline element, such as <strong>, in their line stay one run of text, env-button-text, spaced by their own word spaces.
Customize
Parts the anatomy doesn't show: the spinner, env-button-spinner, the end slot, env-button-end, and the group, env-button-group. A container that sets --env-icon-button-hit-area: var(--env-control-height-touch) gives its smaller icon buttons the touch size under a coarse pointer, as Alert and Toast do for their close buttons.
A wrapper of your own that passes a variant and a tone on types them as Button does: ButtonEmphasisProps, the designed pairs of variant and tone, IconButtonEmphasisProps, IconButton's, and ButtonAppearanceProps, the pairs with size, fullWidth and underline.
Accessibility
You provide
- An
aria-labelon every icon-only button and ButtonGroup, or on an IconButton anaria-labelledbythat points to visible text naming it. type="submit"on the button that submits a form.- Routing behind
href, throughLinkProvider. - Focus for after a confirmed action removes the button.
envUI provides
- Native
<button>and<a>, withtype="button". aria-busyandaria-disabledwhile pending.- Announcements of ConfirmButton’s armed state and CopyButton’s result.
role="group"on ButtonGroup.
Props
Button
Starts an action, or goes to a destination with href, in one of five variants and three tones, with optional icons. It renders a native button or link. An icon alone is an IconButton.
| Prop | Type | Description |
|---|---|---|
variantDefault 'primary' | 'primary''secondary''outline''ghost''text' | The emphasis, primary for a group's main action; without it, the container's, such as ghost in a toolbar, and else primary. |
toneDefault 'neutral' | 'neutral''danger''accent' | The meaning: neutral for most actions, danger for one that deletes or ends something, and accent, on a primary only, for a main action that must stand apart from the brand blue. |
underlineDefault false | boolean | Show an underline for the text variant. |
size | 'sm''md''lg' | The control height, sm, md or lg; without it, the container's, and else md. |
fullWidthDefault false | boolean | Fill the width of the container, such as the actions of a narrow form stacked in a column. |
startIcon | ReactNode | A decorative icon before the label, such as IconAdd. |
endIcon | ReactNode | A decorative icon after the label, such as a ChevronRight for a next step. |
end | ReactNode | Quiet content at the far end, such as a shortcut's Kbd, with aria-hidden on its keys and aria-keyshortcuts on the button. |
pendingDefault false | boolean | Its work is running: a spinner turns over it, it keeps its width and name, and presses do nothing. |
disabled | boolean | A disabled button cannot be pressed; a disabled link has no destination, cannot be focused or followed, and reports aria-disabled. |
href | string | The destination: the element is a native link, through the LinkProvider's link component. |
Also accepts the native props of <button> or <a>, such as ref, className and aria-* attributes.
IconButton
A square button that shows its icon alone, named by aria-label or aria-labelledby, such as a close button with the Close cross; with href, a native link. Without a variant it takes its container's, and else the neutral secondary one.
| Prop | Type | Description |
|---|---|---|
aria-labelledby | string | Required when aria-label is not set. The id of visible text that names the action; this or aria-label. |
disabledDefault false | boolean | A disabled button cannot be pressed; a disabled link has no destination, cannot be focused or followed, and reports aria-disabled. |
href | string | The destination: the button is a native link, through the LinkProvider's link component. |
variantDefault 'secondary' | 'primary''secondary''outline''ghost''text' | Required in some forms. The emphasis, as Button's. Without it, the button takes the variant its container gives, such as ghost in a toolbar, and else secondary. |
toneDefault 'neutral' | 'neutral''danger''accent' | The meaning, as Button's. |
aria-label | string | Required when aria-labelledby is not set. The action's name, which assistive technology announces, such as Open settings. |
iconrequired | ReactNode | The icon, such as Settings. |
pendingDefault false | boolean | As Button's: a spinner replaces the icon while the work runs. |
size | 'sm''md''lg' | As Button's: the height, and the width, of the square button. |
Also accepts the native props of <button> or <a>, such as ref, className and aria-* attributes.
ConfirmButton
A button for an action that takes effect at once and cannot be undone. The first press arms it and names the consequence in place; a second press runs it. It disarms after a few seconds, when focus leaves and on Escape.
| Prop | Type | Description |
|---|---|---|
end | ReactNode | Quiet content at the far end, such as a shortcut's Kbd, with aria-hidden on its keys and aria-keyshortcuts on the button. |
size | 'sm''md''lg' | The control height, sm, md or lg; without it, the container's, and else md. |
pendingDefault false | boolean | Its work is running: a spinner turns over it, it keeps its width and name, and presses do nothing. |
underlineDefault false | boolean | Show an underline for the text variant. |
fullWidthDefault false | boolean | Fill the width of the container, such as the actions of a narrow form stacked in a column. |
startIcon | ReactNode | A decorative icon before the label, such as IconAdd. |
endIcon | ReactNode | A decorative icon after the label, such as a ChevronRight for a next step. |
aria-label | string | Required when icon is set. The icon-only button's name at rest, such as Delete draft. |
confirmLabelrequired | ReactNode | The label while armed: what a second press does, short and without a question mark, such as “Remove Morgan”. |
onConfirmrequired | ( | Runs on the second press, while the button is armed. |
armedDurationDefault 4000 | number | How long the button stays armed without a second press, in milliseconds. |
icon | ReactNode | A round icon-only button at rest, named by aria-label. Armed, it shows the icon with the confirm label, so the consequence is still named. |
variantDefault 'outline', or 'secondary' with icon | 'primary''secondary''outline''ghost''text' | The resting appearance; armed, the button is always variant="primary" tone="danger". Without it, the container's variant, such as ghost in a toolbar, and else outline, or secondary for an icon-only button, like IconButton. |
toneDefault 'neutral' | 'neutral''danger''accent' | The resting meaning, as Button's: neutral, or danger on a primary, outline, ghost or text button. |
Also accepts the native props of <button>, such as ref, className and aria-* attributes.
CopyButton
Copies text to the clipboard. Icon-only by default, with its name in a tooltip, or a labelled button with children. After a press the icon becomes a check, and Copied shows in the tooltip and is announced for two seconds, or Couldn’t copy when the clipboard refuses.
| Prop | Type | Description |
|---|---|---|
valuerequired | string( | The text to copy, or a function that returns it, also as a promise, when pressed. |
onCopied | ( | Runs once the text is on the clipboard, with that text. |
write | ( | Writes the text instead of the browser's Clipboard API, such as through a desktop app's clipboard bridge. A rejected promise shows and announces failedLabel. |
size | 'sm''md''lg' | As Button's: sm, md or lg; without it, the control height of the container. |
icon | ReactNode | The icon at rest, ContentCopy by default; a check replaces it once the text is copied. |
copiedLabelDefault 'Copied', or EnvUIProvider's messages.copyButton.copied | string | Shown in the tooltip and announced after copying. |
failedLabelDefault 'Couldn’t copy', or EnvUIProvider's messages.copyButton.failed | string | Shown in the tooltip and announced when nothing could be copied. |
copyLabelDefault 'Copy', or EnvUIProvider's messages.copyButton.copy | string | The button's name, also in an icon-only button's tooltip, where it has none of its own: no aria-label or aria-labelledby, and a label without words, such as an empty string. |
aria-label | string | Required when children is not set. The icon-only button's name, such as Copy link, which its tooltip shows. |
variantDefault 'secondary' | 'primary''secondary''outline''ghost''text' | Required in some forms. The emphasis, as Button's. Without it, the button takes the variant its container gives, such as ghost in a toolbar, and else secondary. |
toneDefault 'neutral' | 'neutral''danger''accent' | The meaning, as Button's. |
children | booleannullCopyButtonLabel | Required when aria-label is not set. Without children, or with children that render nothing, the button is icon-only, named by aria-label, such as Copy link; a blank one leaves it named by copyLabel. |
Also accepts the native props of <button>, such as ref, className and aria-* attributes.
ButtonGroup
Connected buttons keep their own outer corners and share the row inner radius.
| Prop | Type | Description |
|---|---|---|
orientationDefault 'horizontal' | 'horizontal''vertical' | A row of buttons, or a column in which every button is as wide as the group. |
fullWidthDefault false | boolean | Fill the container's width, such as a sidebar's: in a row, labelled buttons share the room the icon-only ones leave, which keep their square size, and a row of icon-only buttons shares it evenly; in a column, every button is as wide as the group. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
Button
env-button- The button.
env-button-content- The button's label and icons.
env-button-end- The quiet content at the button's end, such as a shortcut's keys.
env-button-spinner- The spinner of a pending button.
data-full-width- Present
data-pending- Any value, or present
data-row-target- Any value, or present
data-sizelg·md·smdata-toneaccent·danger·neutraldata-underline- Any value, or present
data-variantghost·outline·primary·secondary·text
IconButton
env-icon-button- The button that shows only an icon.
data-full-width- Present
data-pending- Any value, or present
data-tonedangerdata-variantghost·outline·secondary·text
ConfirmButton
env-confirm-button- The button that asks to confirm before acting.
env-confirm-button-status- The announcement of the confirming state.
CopyButton
env-copy-button- The button that copies a value.
env-copy-button-field- The field that shows the value beside the button.
env-copy-button-status- The announcement that the value was copied.
ButtonGroup
env-button-group- The row or column of related buttons.
data-full-width- Present
data-orientationhorizontal·vertical
Color properties
Each sets a color of one instance, through style or CSS; its hover, focus and press follow it. They are public and versioned.
Button
--env-button-container- The fill, in every variant; the state layers lie over it, and a solid variant takes them instead of its designed hover and press fills.
--env-button-content- The label and icons, and the color of the state layers.
--env-button-outline- The edge, where the variant draws one, such as outline.
--env-button-selected- The fill of a pressed toggle, such as a toolbar button that is on.
--env-button-selected-content- The icon and label of a pressed toggle.
IconButton
--env-button-container- The fill, in every variant; the state layers lie over it, and a solid variant takes them instead of its designed hover and press fills.
--env-button-content- The label and icons, and the color of the state layers.
--env-button-outline- The edge, where the variant draws one, such as outline.
--env-button-selected- The fill of a pressed toggle, such as a toolbar button that is on.
--env-button-selected-content- The icon and label of a pressed toggle.
Strings
EnvUIProvider's messages overrides each, and a component's own label prop wins over it.
messages.confirmButton.armed"Press again to confirm."Announced when the button arms, after its confirm label.messages.copyButton.copy"Copy"The button's name.messages.copyButton.copied"Copied"Shown and announced once the text is copied.messages.copyButton.failed"Couldn’t copy"Shown and announced when the clipboard refuses.messages.copyButton.unavailable"The clipboard is unavailable."Reported when the clipboard is unavailable.
Changelog
- 1.0.0
end, a quiet slot at the far end for a shortcut's keys, in the button's content color, which the search trigger pattern uses. IconButton is the one icon-only button, and takeshref:Button iconOnlyis gone, and CloseButton is an IconButton with the Close cross.variantisprimary,secondary,outline,ghostortext, andtoneisneutral,accentordanger:importantisvariant="primary" tone="accent",destructiveisvariant="primary" tone="danger",outlinedisoutlineandquietisghost. Outline, ghost and text buttons take the danger tone.fullWidth. Buttons take the variant their container gives where they set none. The page isbutton, after the component, and Link has a page of its own. CopyButton takeswrite, a clipboard writer of the application's own. A Badge or DiffStat inside a button takes its colors through their custom properties, which the button sets.- 1.0.0-prerelease.6
A ghost button's press eases in and out as the other variants' do, in the same color, and a button's hover and press land from their first frame.
A text button's press reads apart from its hover: pressed, a text button with a label lays a faint layer of its label's color behind it; a danger one darkens a step under the pointer and another while pressed, as the link blue does, and a pressed link blue is a step deeper in light.
In dark, a danger primary is a saturated red with a white label, the deepest fill beside the soft primary and accent ones, rather than a pastel coral that weighed no more than Save; it lightens a step on hover and deepens a small step pressed, as they do.
In dark, primary and accent primary buttons share one soft lightness and strength, the accent a soft lilac; each lightens a step on hover and, pressed, deepens a small step below rest rather than turning nearly white.
An outline button's focus ring lies on its edge, which takes the ring's color, rather than around a gray or red edge; in dark, a primary button's ring takes the text color.
A label keeps to one line and its button to its width, so a row short of room wraps whole buttons, not their words; a
fullWidthbutton and a ButtonGroup's still wrap their labels. A vertical group of outline buttons shares straight edges, round only at the column's outer corners.An outline button's label and icon take the text color,
--env-color-fg-default, rather than the brand blue, so beside a primary button it reads as the other choice; a text button keeps the link blue. Ghost, outline and text icon buttons in the danger tone lay a faint tint of the danger color on hover and press, from--env-color-bg-danger-subtle-hover, rather than the neutral grey.Every pending button, an icon button's included, shows a spinner of an icon's size centred over its transparent label, in the label's color, and keeps its width and name.
In light, a danger primary darkens on hover and press as the default and accent primaries do; in dark, the soft primaries deepen by a clearer, even step.
A disabled button no longer fades as a whole: its label and icon take
--env-color-fg-disabled, a filled one half the secondary's neutral fill and an outline one the muted edge, so it stays readable, also in dark.An accent primary is a pill like every other button, rather than having square corners.
A ButtonGroup's buttons meet with a hairline between them and small inner corners, so the group reads as one control with pill ends; outline buttons in a group share their edge. A group that mixes an outline, ghost or text button with another variant keeps its buttons apart as whole pills.
- 1.0.0-prerelease.5
An outline button is an edge with no fill at rest, the same on the page, a pane, a card or a popup; hover and press lay a state layer over the surface beneath it.