Button

Triggers an action or event.

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/button.json
Usage
Import from the master file. Pass `variant` for tone and `size` for footprint.
TSImport
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
TSExample
import { Button } from "@/components/ui/button";

export function Example() {
  return <Button variant="default">Click me</Button>;
}
Composition
Anatomy of the Button primitive and ButtonGroup.
Button
└── children (text, icons with data-icon="inline-start" | "inline-end")

ButtonGroup
└── Button[] (joined visually — first/last get rounded ends)

ToggleButton                     (Button that flips its own pressed state)
├── pressed / defaultPressed / onPressedChange
└── activeVariant (pressed) · inactiveVariant (default "outline")

SplitButton                      (primary Button + chevron dropdown)
├── items={[{ label, icon?, onClick, destructive? }]}   (actions-menu mode)
└── options={[{ label, description? }]} + onAction       (selectable/radio mode)

LongPressButton                  (press-and-hold to fire; own page/file)
└── onHoldComplete · holdDuration (default 1600ms) · onHoldCancel
Variants
Ten stylistic variants out of the box. `tonal` inherits the surrounding `currentColor` so the button auto-tints to whatever surface it sits on (try it inside a warning Alert with `actionButton`).
Fancy
`variant="fancy"` is the glossy pill — a top-lit vertical gradient with a refined triple inset/drop shadow (top white highlight + bottom inner shadow + soft drop) and a hairline ring, scaling down slightly on press. Pick a tone with the `color` prop (`brand` | `coral` | `destructive` | `warning` | `success` | `ghost`, defaulting to `brand`); `ghost` is the neutral dark glossy button. Pass `className` only to override beyond those presets.
Fancy — with icons
Same glossy pill with icons. Mark a child icon with `data-icon="inline-start"` / `"inline-end"` for optical padding beside the label, or pass `size="icon"` for an icon-only button.
Fancy — loading
Loading state: drop a `<Spinner color="current" data-icon="inline-start" />` (use `color="current"` so the spinner matches the button text) into a `fancy` button and set `disabled` while the async action runs.
Long press
`<LongPressButton>` requires a press-and-hold to fire — a progress sweep fills over `holdDuration` (default 1600ms) and releasing early cancels (`onHoldCancel`); completing fires `onHoldComplete`. Works with pointer and keyboard (Space/Enter), respects reduced-motion, and takes the same `variant`/`size` props as Button. Good for destructive confirmations.
Tonal (inherits surrounding color)
`variant="tonal"` styles the button with `bg-current/10 text-current` so it picks up whatever `currentColor` the parent surface establishes. Drop one inside any tinted card, alert, or banner and it auto-matches without any per-tone wiring.
Neutral
Brand
Info
Success
Warning
Destructive
Sizes
Three text sizes plus matching icon-only sizes.
Wide
Always stretches to fill its container — ideal for form submits and full-width CTAs.
With icons
Icons can sit inline on either side of the label.
States
Default, hover, and disabled behavior per variant.
Toggle (outline ↔ primary)
`<ToggleButton>` manages its own pressed state — `inactiveVariant` (defaults to `outline`) when off, `activeVariant` (defaults to `default`/primary) when on, with `aria-pressed` wired automatically. Use uncontrolled (`defaultPressed`) or controlled (`pressed` + `onPressedChange`). The last row drives both the variant and label from state — an outline **And** that flips to a coral **Or**.
Button group
Adjacent buttons joined into a single control.
Button group with dropdown
Split button — primary action on the left, a dropdown menu on the right lets the user switch the action.
Button group with action menu
Primary button keeps its action; the dropdown contains separate secondary actions that each fire their own handler when clicked.
API Reference
Props exposed by Button, ButtonGroup, ToggleButton, and SplitButton.

Button

PropTypeDefaultDescription
variant"default" | "fancy" | "fancy-outline" | "secondary" | "outline" | "ghost" | "destructive" | "destructive-solid" | "link" | "soft" | "tonal" | "coral" | "transparent""default"Visual tone. `default` is brand violet; `fancy` is the glossy gradient pill; `soft` is the tinted treatment.
color"brand" | "coral" | "destructive" | "warning" | "success" | "ghost""brand"Tone for `variant="fancy"` (ignored by other variants). `className` still overrides.
size"xs" | "sm" | "default" | "xl" | "wide" | "icon" | "icon-xs" | "icon-sm" | "icon-xl""default"`wide` stretches to fill its container. The `icon-*` sizes pair with a single child icon and `aria-label`.
renderReactElementBase UI render-prop — pass another element (e.g. `<Link/>`) to swap the underlying tag.
classNamestringOverride or extend the resolved variant classes.

ButtonGroup

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Stack adjacent buttons inline or vertically.
classNamestringAdditional classes applied to the group wrapper.

ToggleButton

PropTypeDefaultDescription
pressedbooleanControlled pressed state. Pair with `onPressedChange`.
defaultPressedbooleanfalseUncontrolled initial pressed state.
onPressedChange(pressed: boolean) => voidFires with the next pressed state on click.
activeVariantButtonVariant"default"Variant rendered while pressed (primary by default).
inactiveVariantButtonVariant"outline"Variant rendered while not pressed.
sizeButtonSize"default"Same size scale as Button.

SplitButton

PropTypeDefaultDescription
labelReactNodePrimary button label (actions-menu mode). Ignored when `options` is set.
onClick() => voidPrimary button click handler.
itemsSplitButtonItem[]Action items in the chevron dropdown: `{ label, icon?, onClick?, disabled?, destructive? }`.
optionsSplitButtonOption[]Radio options `{ label, description?, disabled? }`. When set, the primary button's label is the active option (selectable mode).
defaultValuenumber0Initial selected index in selectable mode.
valuenumberControlled selected index. Pair with `onValueChange`.
onValueChange(index: number) => voidFires when the selected index changes (selectable mode).
onAction(option, index) => voidFires when the primary button is activated (selectable mode).
variantButtonVariantVariant applied to both the primary and chevron buttons.
sizeButtonSizeSize applied to both buttons.
chevronLabelstring"More actions"Accessible label for the chevron trigger.