Button

One box, four ranks of emphasis. It owns the fill, the states and the focus ring, so an icon inside it never carries a second box of its own.

import { Button } from "@dede-style/ui/button", then <Button>Save</Button>. The words are the label and the accessible name at once. For a button with no words, see IconButton — same code underneath, one extra rule.

PropDescriptionDefaultControl
variantemphasis: primary for the main action (one per view), secondary (default), tertiary for the quietest, destructive for a dangerous actionprimarysecondarytertiarydestructivesecondary
  • primary
  • secondary
  • tertiary
  • destructive
sizeheight: 24, 32, 40 or 48px. 24 is for icon buttons only68101210
  • 6
  • 8
  • 10
  • 12
shapecorners: rounded (default), pill or squareroundedpillsquarerounded
  • rounded
  • pill
  • square
glyphan optional icon beside the label. In code, import it by its full name: icon plus this (Star is iconStar)noneAlertAlertFillArrowDownArrowLeftArrowRightArrowUpBag+91 morenone
  • none
  • Alert
  • AlertFill
  • ArrowDown
  • ArrowLeft
  • ArrowRight
  • ArrowUp
  • Bag
  • Bell
  • BellRing
  • BellSlash
  • Bluetooth
  • Bookmark
  • BookmarkFill
  • Calendar
  • Camera
  • Cart
  • Check
  • CheckBold
  • Checkbox
  • CheckboxChecked
  • CheckboxMixed
  • ChevronDown
  • ChevronLeft
  • ChevronRight
  • ChevronUp
  • ChevronsDownUp
  • ChevronsLeft
  • ChevronsRight
  • ChevronsUpDown
  • Clock
  • Close
  • Code
  • CodeAlt
  • Cookie
  • Copy
  • CreditCard
  • DataChart
  • DataColumns
  • DataGrid
  • DataRows
  • Delete
  • Download
  • DragHandle
  • Edit
  • Email
  • Error
  • ErrorFill
  • ExternalLink
  • Eye
  • EyeSlash
  • File
  • Filter
  • Folder
  • Github
  • Heart
  • HeartFill
  • Help
  • HelpFill
  • Home
  • Image
  • Info
  • InfoFill
  • Link
  • Lock
  • LockOpen
  • LogOut
  • Menu
  • Minus
  • MinusBold
  • Moon
  • MoreHorizontal
  • MoreVertical
  • Pause
  • Placeholder
  • Play
  • Plus
  • Radio
  • RadioChecked
  • Refresh
  • Search
  • Settings
  • Share
  • Shield
  • Star
  • StarFill
  • Stop
  • Success
  • SuccessFill
  • Sun
  • SwapVertical
  • Tag
  • TagFill
  • Upload
  • User
  • Warning
  • WarningFill
  • Wifi
  • WifiSlash
isDisableddisables the button and dims itfalse
fullWidthfill the container's width. Off, the button fits its labelfalse
typethe HTML button type. Default button, so it never submits a form by accident; use submit to submitbuttonsubmitresetbutton
  • button
  • submit
  • reset

Tokens

What a theme can move, where the props above are what an instance can move.

TokenDescriptionLightDark
--button-radius-roundedwhat shape="rounded" resolves to. Only that shape — pill and square are statements rather than values, so a theme setting this to 0 squares the rounded buttons and leaves pills round--radius-4--radius-4
--button-bg-primarythe solid fill. A token rather than the text role, because a fill that happens to match the text colour is still a fill--neutral-20--neutral-98
--button-bg-secondarythe soft fill — a resting wash of the same ink the interaction states use, so it darkens on light and lightens on dark. The two modes carry different strengths, which is the one place they disagreecolor-mix(in srgb, var(--neutral-20) var(--opacity-1), transparent)color-mix(in srgb, var(--neutral-98) var(--opacity-2), transparent)
--button-bg-destructivethe coloured fill. Points at --color-error by default; a theme can move the button without moving every other error in the system--color-error--color-error

A token appears here only when the value is not already reachable. Anything that resolves through a foundation token or a role needs none, because overriding that already moves it — and a second dial wired to the same value would let this one component drift from everything sharing the role. What is left is the values with no other lever at all.

These are public and overridable — there is no private custom property, because anything on :root is reachable by any stylesheet. What replaces privacy is a stability contract: primitives may move, roles are the guarantee, and these are the per-component escape from both.