Components

Button

Triggers a user action. The main action of a screen or form. Follows shadcn structure with the Yuno primary color.

Updated Jul 16, 2026 by Leonardo Posada

Variants

<Button>Continue</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>

Sizes

<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
<Button size="icon"><Plus weight="light" /></Button>

With icons

<Button>Continue <ArrowRight weight="light" /></Button>
<Button variant="outline"><MagnifyingGlass weight="light" /> Search</Button>
<Button><Trash weight="light" /> Delete rule</Button>

States

<Button disabled>Disabled</Button>
<Button variant="outline" disabled>Disabled</Button>

When to use

  • As the primary CTA of a screen or section.
  • For Submit / Save / Cancel inside a form.
  • To trigger a Dialog or Sheet.
  • For row-level actions in tables (usually variant='ghost' or 'outline').

When not to use

  • For navigation between pages — use next/link with anchor styling.
  • As a long list of options — use a Select or a Menu instead.
  • For toggles or booleans — use Switch or Checkbox.

Usage

Do
  • One Primary button per screen.
  • Include a Phosphor icon with the label when it adds meaning (arrow for continue, trash for delete).
  • For destructive actions (delete rules, lists, routes), use variant='default' (Primary) — clarity comes from the copy, not the color.
  • Group Cancel + Confirm together with Cancel on the left, Confirm on the right.
Don't
  • Don't stack multiple Primary buttons in the same view.
  • Don't hardcode background colors — use variants.
  • Don't use variant='destructive' (red) — it is not part of the Yuno Dashboard vocabulary.
  • Don't use variant='link' when you actually mean a real link — use next/link.
  • Don't make icon-only buttons without an aria-label.

Recipes

Ready-to-copy compositions covering the most common Yuno usages of this atom.

Primary CTA

One primary button per screen, with an optional trailing icon that reinforces the action (ArrowRight for continue).

<Button>
  Continue <ArrowRight weight="light" />
</Button>
Dialog footer (Cancel + Confirm)

Cancel (outline, on the left) + primary Confirm (right) inside a DialogFooter. Canonical pattern for confirmations.

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">Delete rule</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Delete rule?</DialogTitle>
      <DialogDescription>
        Transactions matching this rule will stop being evaluated.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose asChild>
        <Button variant="outline">Cancel</Button>
      </DialogClose>
      <Button>Delete rule</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
Icon-only with tooltip

3-dots (DotsThreeOutline, fill) trigger with the Yuno table-row hover style (border + bg + shadow-xs on hover, tokens on data-[state=open]). Wrap in a Tooltip.

<TooltipProvider>
  <Tooltip>
    <TooltipTrigger asChild>
      <button
        type="button"
        aria-label="Actions"
        className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-transparent bg-transparent text-muted-foreground transition-all hover:border-border hover:bg-background hover:text-foreground hover:shadow-xs data-[state=open]:border-border data-[state=open]:bg-background data-[state=open]:text-foreground"
      >
        <DotsThreeOutline weight="fill" className="size-4" />
      </button>
    </TooltipTrigger>
    <TooltipContent side="top" sideOffset={6}>Actions</TooltipContent>
  </Tooltip>
</TooltipProvider>
Loading state

Button disabled while a request is in flight, with a spinner icon replacing the leading icon. Prevents double-submits.

function LoadingButton() {
  const [loading, setLoading] = React.useState(false);
  return (
    <Button
      onClick={() => { setLoading(true); /* fire request */ }}
      disabled={loading}
    >
      {loading ? (
        <><CircleNotch weight="light" className="animate-spin" /> Saving…</>
      ) : (
        <><Pencil weight="light" /> Save rule</>
      )}
    </Button>
  );
}

Import

Copy this import line at the top of the file where you compose this atom.

Base import + Phosphor icon example.
import { Button } from "@/components/ui/button";
import { ArrowRight } from "@phosphor-icons/react/dist/ssr";

Props

Everything else from the underlying HTML or Radix primitive is forwarded via ...props.

PropTypeDefaultDescription
variant"default" | "secondary" | "outline" | "ghost" | "link""default"Visual variant. Note: destructive is not used at Yuno — see the callout below.
size"default" | "sm" | "lg" | "icon""default"Height + padding preset. Use 'icon' for square icon-only buttons (size-9).
asChildbooleanfalseMerge props onto the child element (Radix Slot). Use to make the Button render as an <a> or <Link>.
disabledbooleanfalseNative disabled attribute. Dims the button and blocks interaction.
type"button" | "submit" | "reset""button"Native button type. Always set 'submit' explicitly when the Button is inside a <form>.
classNamestringMerged with the variant class list via cn().

Related

Cross-links to atoms and patterns you may reach for next.

  • DialogThe canonical place to put a delete / confirmation Button pair.
  • TooltipWrap icon-only buttons to expose their meaning to sighted + AT users.
  • Dropdown menuFor 3+ related actions grouped behind one trigger.
  • ToggleWhen the button represents a persistent on/off state (like bold in a rich text editor).

Not used at Yuno

Not used at Yuno
The red (destructive) button is not used in the Yuno Dashboard.
Red communicates 'alert' or 'danger', but most 'destructive' actions at Yuno — deleting a rule, list, or route — are perfectly normal operations. Coloring them red overloads the emotional weight and makes the interface feel more anxious than it should. Yuno uses the Primary button for these actions and lets the copy carry the meaning.
Not used at Yuno

Use Primary instead

For deletes and other 'destructive' flows, use the Primary button inside a Dialog. Clarity comes from the copy ('Delete rule?'), not from the color.

<Dialog>
  <DialogTrigger asChild>
    <Button variant="ghost" size="sm">
      <Trash weight="light" /> Delete rule
    </Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Delete rule?</DialogTitle>
      <DialogDescription>
        Transactions matching this rule will stop being evaluated.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose asChild>
        <Button variant="outline">Cancel</Button>
      </DialogClose>
      <Button>Delete rule</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>