crispmeasured from Attio

Button

A pressable action trigger with four intents, three sizes, and text or icon-only shapes.

Measured from Attio — brand #266df0, heights 28/32/40px, radii r8/r9/r10.

Preview

Installation

bun add crisp
import "crisp/styles.css";
import { Button } from "crisp";

Usage

import { Button } from "crisp";

export function Example() {
  return (
    <Button intent="primary" size="md">
      Save
    </Button>
  );
}

Props

PropTypeDefaultDescription
intent"primary" | "neutral" | "danger" | "ghost""primary"Sets the button's color role and visual weight.
size"sm" | "md" | "lg""md"Sets height, padding, and font size — 28 / 32 / 40px.
shape"text" | "icon""text""icon" removes horizontal padding and forces a square, 1:1 aspect ratio.
loadingbooleanfalseShows a spinner, disables the button, and sets aria-busy.
asChildbooleanfalseRenders the passed child element instead of a <button>, forwarding classes (polymorphic).
...propsComponentPropsWithoutRef<"button">All native button attributes: onClick, disabled, type, etc.

Examples

Intent

All four intents — neutral and ghost measured from Attio's toolbar, primary and danger from its primary CTAs.

<Button intent="primary">Save</Button>
<Button intent="neutral">Cancel</Button>
<Button intent="danger">Delete</Button>
<Button intent="ghost">Dismiss</Button>

Size

Three heights: 28px (sm), 32px (md), 40px (lg).

<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

With icons

Pass an <svg> as a leading or trailing child — the button's gap: 6px handles spacing.

<Button intent="primary">
  <PlusIcon />
  New task
</Button>

<Button intent="neutral">
  Export
  <ChevronDownIcon />
</Button>

Icon-only

shape="icon" produces a square button. Always pass aria-label since there is no visible text.

<Button intent="neutral" shape="icon" aria-label="Settings">
  <GearIcon />
</Button>

Loading

loading shows a self-animating spinner, disables the button, and sets aria-busy="true".

<Button intent="primary" loading>
  Saving…
</Button>

Disabled

Native disabled — 50% opacity, pointer disabled.

<Button intent="primary" disabled>Save</Button>
<Button intent="neutral" disabled>Cancel</Button>

asChild

Polymorphic rendering — the button's classes and behavior are forwarded onto the child element instead of a <button>. Here it renders an <a>.

<Button intent="primary" asChild>
  <a href="/tasks/new">New task</a>
</Button>

Accessibility

Button preserves the browser's default focus-visible outline — crisp does not suppress or override it. When using shape="icon", always provide an accessible name via aria-label or aria-labelledby, since there is no visible text for assistive technology to read. loading sets both disabled and aria-busy="true", so screen readers announce the busy state and duplicate submissions are prevented.

KeyAction
Enter / SpaceActivates the focused button.
TabMoves focus to the next focusable element.

On this page