Button
Runs an action. Use one main button per screen, and quieter ones around it.
SourcePackage @weft-js/warpPlayground
Preview
import { Button } from '@weft-js/warp'export function Default() { return ( <Button>Deploy</Button> )}Installation
npm install @weft-js/warpUsage
import { Button } from '@weft-js/warp'<Button>Deploy</Button>Variants
Use emphasis to set how loud the button is, from solid down to link.
import { Button } from '@weft-js/warp'export function Emphasis() { return ( <> <Button>Deploy</Button> <Button emphasis="frame">Deploy</Button> <Button emphasis="soft">Deploy</Button> <Button emphasis="outline">Deploy</Button> <Button emphasis="ghost">Deploy</Button> <Button emphasis="link">Deploy</Button> </> )}Sizes
Use size for sm, md or lg.
import { Button } from '@weft-js/warp'export function Sizes() { return ( <> <Button size="sm">Deploy</Button> <Button>Deploy</Button> <Button size="lg">Deploy</Button> </> )}Tones
Use tone to say what the action means. critical is for anything destructive.
import { Button, Row, Stack } from '@weft-js/warp'export function Tones() { return ( <Stack gap="related"> {TONES.map(tone => ( <Row key={tone} gap="related"> <Button tone={tone}>Deploy</Button> <Button tone={tone} emphasis="soft">Deploy</Button> <Button tone={tone} emphasis="outline">Deploy</Button> <Button tone={tone} emphasis="ghost">Deploy</Button> </Row> ))} </Stack> )}const TONES = ['neutral', 'accent', 'positive', 'caution', 'critical', 'info'] as constFill that follows
By default the fill wipes in from the left and out to the right. Add follow and, at vivid, it spreads from where the pointer comes in instead.
import { Button } from '@weft-js/warp'export function Follow() { return ( <> <Button>Wipe</Button> <Button follow>Follow</Button> <Button follow emphasis="soft">Follow</Button> <Button follow emphasis="outline" tone="neutral">Follow</Button> </> )}Icons
Use icon to draw one before the label.
import { Button } from '@weft-js/warp'export function WithIcon() { return ( <> <Button icon="rocket">Deploy</Button> <Button emphasis="outline" tone="neutral" icon="plus">New project</Button> <Button emphasis="ghost" tone="critical" icon="trash">Delete</Button> </> )}Icon only
Needs label: it becomes the accessible name.
import { Button } from '@weft-js/warp'export function IconOnly() { return ( <> <Button icon="plus" label="New project" /> <Button emphasis="outline" tone="neutral" icon="settings" label="Settings" /> <Button emphasis="ghost" tone="neutral" icon="trash" label="Delete" /> </> )}Full width
Use full to take the width of the container.
import { Button } from '@weft-js/warp'export function Full() { return ( <Button full>Deploy to production</Button> )}Loading
The label stays the accessible name, presses are swallowed and focus stays put.
import { Button } from '@weft-js/warp'export function Loading() { return ( <> <Button loading>Deploying</Button> <Button emphasis="outline" tone="neutral" loading>Deploying</Button> </> )}Disabled
Prefer aria-disabled: the button stays focusable, so people can find out why.
import { Button } from '@weft-js/warp'export function Disabled() { return ( <> <Button aria-disabled="true">Deploy</Button> <Button emphasis="outline" tone="neutral" aria-disabled="true">Deploy</Button> <Button disabled>Deploy</Button> </> )}Delete confirmation
Give the confirming button tone="critical" and the way out a quiet ghost button.
import { Button, Row, Stack, Text } from '@weft-js/warp'export function DeleteProject() { return ( <Stack gap="related"> <Text role="heading">Delete storefront?</Text> <Text subtle>Its 412 deploys and all its logs go too. This can't be undone.</Text> <Row gap="related" justify="end"> <Button emphasis="ghost" tone="neutral">Keep it</Button> <Button tone="critical">Delete project</Button> </Row> </Stack> )}Empty state
A single button with an icon gives an empty view one clear next step.
import { Button, Stack, Text } from '@weft-js/warp'export function EmptyState() { return ( <Stack gap="related" align="center"> <Text role="heading">No projects yet</Text> <Text subtle>Connect a repository and your first deploy runs in about a minute.</Text> <Button icon="plus">New project</Button> </Stack> )}Save with progress
Set loading while the work runs, then confirm with a toast.
import { state } from '@weft-js/core'import { Button, Toaster, toast } from '@weft-js/warp'export function SaveAsync() { const saving = state(false) const save = async () => { saving.value = true await new Promise(done => { setTimeout(done, 1500) }) saving.value = false toast.show({ title: 'Saved', description: 'Your changes are live.' }) } return ( <> <Button loading={saving.value} onClick={save}>{saving.value ? 'Saving' : 'Save changes'}</Button> <Toaster /> </> )}When to use
Playground
import { Button } from '@weft-js/warp'<Button>Deploy</Button>Accessibility
- Enter
- Presses the button
- Space
- Presses the button
- It is a real
<button>, so it works with every assistive technology and inside forms. - An icon-only button must have
label.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
emphasis | Emphasis | 'solid' | solid (default) · soft · outline · ghost · frame (the signature) · link. Fixed at creation: it picks the anatomy. |
tone | Tone | — | What the action means. critical for anything destructive. |
size | "sm" | "md" | "lg" | — | sm, md or lg. Each follows the density around it. |
fill | boolean | false | A frame button with the solid fill sweeping in. |
follow | boolean | false | At vivid, the hover fill spreads from where the pointer comes in instead of wiping in from the left. |
full | boolean | false | Takes the whole width of its container. |
icon | IconRef | — | An icon before the label. Alone, it needs label. |
collapse | "tablet" | "phone" | — | With icon and text: on a phone (or a tablet and a phone) only the icon shows, and the text stays the accessible name. |
label | string | — | The accessible name, for an icon-only button. |
loading | boolean | false | Shows a spinner, keeps the button's width and swallows presses. |
children | unknown | — | What it contains. |
| Event | Type | Default | Description |
|---|---|---|---|
onClick | ((e: MouseEvent) => unknown) | — | Called when pressed. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="button"] [data-part="collapse"]
collapsesweep-fillframe-cornerssweep-cornerssweep-outlinesweep-labelsweep-contentlabelspinnersweep