Button
Generic button primitive. It names a role, never a look: what each role
looks like is the brand's, and lives in layered CSS keyed off the attributes
below. So there is no outline, ghost or link — those are results of a
brand's definitions — and no size, because a size scale is a fixed set of
appearance decisions a package cannot make for every brand.
import { Button } from "@evolve-storefront/ui/button";Preview
Usage
The action this view wants taken. At most one per region.
<Button variant="primary" type="submit" isPending={isPending}> {t("placeOrder")}</Button>;Props
| Prop | Type | Description |
|---|---|---|
variant? | ButtonVariant | |
tone? | ButtonTone | |
isIconOnly? | boolean | The button has no visible label, so it is square. Structural rather than a size: it says the button has nothing to be wide for, and says nothing about how big — the brand's control tokens still decide that. MoreNot inferred from the children. A kebab menu is as often a glyph or an SVG
as an |
asChild? | boolean | |
type? | "button" | "submit" | "reset" | |
isPending? | boolean | The action is running. The button keeps its label, so its width and
accessible name hold, shows a spinner and is |
data-component? | undefined | A button's identity is not a caller's to rename — see |
Any other props go to the root element, like on a plain HTML element.
Examples
SecondaryA real alternative, equally available, not competing for the eye.
<Button variant="secondary" onClick={saveForLater}> {t("saveForLater")}</Button>;TertiaryReachable without adding weight — row actions, dismissals, dense UI.
<Button variant="tertiary" onClick={onDismiss}> {t("dismiss")}</Button>;Disabled
<Button type="submit" disabled={!canSubmit}> {t("submit")}</Button>;PendingThe action is running: a spinner over the label, which stays in place so the button keeps its width and name.
<Button type="submit" isPending={mutation.isPending}> {t("continue")}</Button>;As child (link)
<Button asChild> <a href="/orders">View orders</a></Button>VariantsRank and tone are orthogonal, which is the point of splitting them: the confirm in a delete dialog is the loudest thing on it and the dangerous one, and a line-item delete is the same tone at a quieter rank.
<Button variant="primary">Place order</Button><Button variant="tertiary" tone="destructive">Remove</Button><Button variant="primary" tone="destructive">Delete account</Button>Icon onlyNo visible label, so nothing to be wide for.
<Button variant="tertiary" isIconOnly aria-label="More actions"> <Icon name="more" /></Button>Trigger in a formA trigger's child inside a form opens its overlay and leaves the form alone.
<SheetTrigger asChild> <Button variant="secondary">Search all addresses</Button></SheetTrigger>
