Button

Clickable button with multiple variants and sizes.

$ npx @beaket/ui add button
Source
import { Button } from "@/components/ui/button";

export default function AllVariantsExample() {
  return (
    <div className="flex flex-wrap gap-2">
      <Button variant="primary">Primary</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
      <Button variant="success">Success</Button>
      <Button variant="warning">Warning</Button>
    </div>
  );
}

Examples

All Sizes

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

export default function AllSizesExample() {
  return (
    <div className="flex items-center gap-2">
      <Button size="sm">Small</Button>
      <Button size="md">Medium</Button>
      <Button size="lg">Large</Button>
      <Button size="icon">+</Button>
    </div>
  );
}

All States

primary
Rest
Held-open
Pressed
Disabled
Loading
outline
Rest
Held-open
Pressed
Disabled
Loading
Source
import { Button } from "@/components/ui/button";
import type { ReactNode } from "react";

function StateCell({ label, children }: { label: string; children: ReactNode }) {
  return (
    <div className="flex flex-col items-center gap-2">
      {children}
      <span className="text-fg-subtle text-xs">{label}</span>
    </div>
  );
}

function StateRow({
  variant,
  pressedClassName,
}: {
  variant: "primary" | "outline";
  pressedClassName: string;
}) {
  return (
    <div className="flex flex-col gap-3">
      <span className="text-fg-muted text-sm font-medium">{variant}</span>
      <div className="flex flex-wrap items-start gap-6">
        <StateCell label="Rest">
          <Button variant={variant}>Button</Button>
        </StateCell>
        <StateCell label="Held-open">
          <Button variant={variant} data-state="open">
            Button
          </Button>
        </StateCell>
        <StateCell label="Pressed">
          <Button
            variant={variant}
            className={pressedClassName}
            style={{ boxShadow: "none", transform: "translate(1px, 1px)" }}
          >
            Button
          </Button>
        </StateCell>
        <StateCell label="Disabled">
          <Button variant={variant} disabled>
            Button
          </Button>
        </StateCell>
        <StateCell label="Loading">
          <Button variant={variant} loading>
            Button
          </Button>
        </StateCell>
      </div>
    </div>
  );
}

export default function AllStatesExample() {
  return (
    <div className="flex flex-col gap-8">
      <StateRow variant="primary" pressedClassName="bg-bg-emphasis-active" />
      <StateRow variant="outline" pressedClassName="bg-bg-active" />
    </div>
  );
}

Props

NameTypeDefaultDescription
variantundefined | link | primary | danger | destructive | outline | secondary | ghost | success | warning—Button style. Prefer danger for the semantic role; destructive remains an alias.
sizeundefined | sm | md | lg | iconmdsm | md | lg | icon. Button size
loadingboolean | undefined—Shows a loading spinner and disables the button. Left unset on a `type="submit"` button inside a `<form>`, it follows the form's own pending state. Set it explicitly to override that either way.
loadingLabelstring | undefinedLoadingAccessible name of the loading spinner. Defaults to Loading.
asChildboolean | undefinedfalseMerges props onto the immediate child element instead of rendering a button