Button
macOS 26 Push Button — 6 variants × 5 sizes (heights 16/20/24/28/36) × states.
macOS-style push buttons lifted from the Apple macOS 26 UI Kit: a prominent
solid default, three low-emphasis tinted colors (secondary, destructive,
neutral), a borderless neutral ghost, and a borderless accent link.
Per-size corner radius and an orthogonal icon shape, theme-aware via the
Acrylic token set (colors flip light/dark).
Installation
npx shadcn add https://acrylic-ui.vercel.app/r/button.jsonUsage
"use client"import { ArrowRight } from "lucide-react"import { Button } from "@/registry/acrylic/button"export default function ButtonDemo() { return ( <div className="flex flex-wrap items-center gap-2"> <Button>Default</Button> <Button variant="secondary">Secondary</Button> <Button variant="destructive">Destructive</Button> <Button variant="neutral">Neutral</Button> <Button variant="ghost">Ghost</Button> <Button variant="link">Link</Button> <Button icon variant="neutral" aria-label="Next"> <ArrowRight /> </Button> </div> )}import { Button } from "@/components/acrylic/button"
<Button variant="secondary" size="large">Label</Button>Variants
| variant | macOS class | look | emphasis |
|---|---|---|---|
default | Bordered Default | solid accent fill, white label (System Blue) | high |
secondary | Bordered Secondary | 10% accent tint, accent label | low |
destructive | Bordered Destructive | 25% red tint, red label (System Red) | low |
neutral | Neutral | translucent gray fill, foreground label | low |
ghost | Borderless Neutral | foreground label/glyph, no fill at rest | low |
link | Borderless Accent | accent label, no button chrome | low |
Sizes
mini (16px) · small (20) · medium (24, default) · large (28) · xl (36).
Corner radius is taken straight from the kit and is not a single formula —
mini/small/medium stay quarter-height rounded rectangles while large/xl snap to a
full capsule:
| size | mini | small | medium | large | xl |
|---|---|---|---|---|---|
| radius | 4 | 5 | 6 | 14 | 18 |
Icon buttons
icon is an orthogonal boolean — not a size. It turns any size × variant
into the kit's round Arrow Button: square (diameter = the size's height), full-circle
radius, no padding, with the glyph scaled to the size. So it composes freely:
<Button icon aria-label="Next"><ArrowRight /></Button> {/* medium, default */}
<Button icon size="large" variant="ghost"><Trash2 /></Button> {/* large round ghost */}
<Button icon size="mini" variant="destructive"><X /></Button> {/* mini round red */}Icon + label
A leading or trailing icon sits inline with the label (flex, items-center,
gap-1). The kit renders icon + label as a single SF run — glyph + one space —
so the gap is ~one SF Pro space (≈4px), not a looser 6–8px. The glyph scales with
the control size and stays optically centered with the text:
"use client"import { ArrowRight, Download, Plus, Settings, Trash2 } from "lucide-react"import { Button } from "@/registry/acrylic/button"const sizes = ["mini", "small", "medium", "large", "xl"] as const// Icon + label combinations — the case the variant/size matrix doesn't cover.// Three rows to eyeball alignment: a leading icon across every size (does the// glyph stay optically centered with the label as the height grows?), a trailing// icon across every size, and a leading icon across every variant.export default function ButtonIconText() { return ( <div className="flex flex-col gap-4"> {/* leading icon + label, every control size */} <div className="flex flex-wrap items-center gap-3"> {sizes.map((size) => ( <Button key={size} size={size}> <Plus /> New </Button> ))} </div> {/* label + trailing icon, every control size */} <div className="flex flex-wrap items-center gap-3"> {sizes.map((size) => ( <Button key={size} size={size} variant="neutral"> Continue <ArrowRight /> </Button> ))} </div> {/* leading icon + label, every variant (medium) */} <div className="flex flex-wrap items-center gap-3"> <Button> <Download /> Download </Button> <Button variant="secondary"> <Settings /> Settings </Button> <Button variant="destructive"> <Trash2 /> Delete </Button> <Button variant="neutral"> <Plus /> Add </Button> <Button variant="ghost"> <Plus /> Add </Button> <Button variant="link"> <Plus /> Learn more </Button> </div> </div> )}Showcase
Every variant in every size (plus a round icon button per variant):
"use client"import { ArrowRight } from "lucide-react"import { Button } from "@/registry/acrylic/button"const variants = ["default", "secondary", "destructive", "neutral", "ghost", "link"] as constconst sizes = ["mini", "small", "medium", "large", "xl"] as const// The full matrix: every variant (rows) in every macOS control size (columns),// plus a round icon button per variant. Lifted from the Apple macOS 26 UI Kit// Buttons page. The last row shows `icon` scaling across all five sizes.export default function ButtonShowcase() { return ( <div className="flex flex-col gap-3"> {variants.map((variant) => ( <div key={variant} className="flex flex-wrap items-center gap-3"> {sizes.map((size) => ( <Button key={size} variant={variant} size={size}> {variant} </Button> ))} <Button variant={variant} icon aria-label={`${variant} icon`}> <ArrowRight /> </Button> </div> ))} {/* icon buttons scale with size — diameter = the control height (16…36) */} <div className="flex flex-wrap items-center gap-3"> {sizes.map((size) => ( <Button key={size} icon size={size} variant="neutral" aria-label={`icon ${size}`}> <ArrowRight /> </Button> ))} </div> </div> )}Breadcrumb
shadcn's Breadcrumb, anatomy and API unchanged — already token-driven, so it flips light/dark/acrylic for free; the only acrylic touch is quieter separator glyphs.
Button Group
macOS 26 grouped control — attached buttons in a gray well, a backgroundless ghost group, a selectable segmented control with a raised white pill, or a split group.