Button

shadcn/ui button (radix-nova) on DESIGN.md tokens. One filled action per view; everything else is bordered, soft or text. Press any of them: a 0.97 squash plus a ripple from the pointer, both ease-out.

import { Button } from "@stocklots/ui-components/components/button";

<Button variant="outline" size="sm">Save changes</Button>

Variants

default = primary action · secondary = quiet fill · outline = bordered · ghost = text · destructive / success / warning / info / hold = soft status · link = inline

Website variants

brand = green fill, navy label · inverse = white outline, white label · inverse-brand = green outline, white label. For dark brand surfaces and photos (hero, CTA band, audience cards); never on the page surface.

Sizes

Heights 28 / 32 / 40 / 48 on the 4px grid.

Icon sizes

Square, same heights as the text sizes.

With icon

Mark the icon data-icon="inline-start" | "inline-end" so padding tightens on that side.

Disabled

50% opacity, not-allowed cursor, no hover reaction. Still receives pointer events so a tooltip can say why. Pair with visible copy that says why, e.g. "Approve (waiting on bank)".

Waiting on the bank

Loading

loading reserves the width of both labels, disables the control and sets aria-busy. Toggle to compare.

Success and error

success / error show an animated check or cross with their text, keep the width, and re-enable the button so the user can retry. Press to run save → outcome → idle; error is paired with an inline message beside the button.

As child

asChild renders the styles onto another element, here a Next.js Link. Disabled becomes aria-disabled and the click is blocked.