Button

Buttons trigger actions. Use the brand variant for the one main action on a surface, lower-emphasis variants for everything else.

Examples

Variants

Sizes

With icons

Loading

Disabled

Icon only

Rounded

Overview

Button is the primary interactive element for triggering actions. It supports multiple variants for different emphasis levels, five sizes, icons, loading states, and accessibility features out of the box.

tsx
import { Button } from "@rogo-technologies/ui/button";

<Button variant="brand" size="md">
  Click me
</Button>;

Usage

Variants

Variants encode emphasis, not taste — pick by the action's role on the surface, not by how much attention you'd like it to get. The emphasis ladder, highest to lowest: brandoutline / mutedghosttext / link. destructive sits outside the ladder: it encodes danger, not importance.

Always write variant explicitly. The default is brand, so a <Button> without a variant silently becomes a primary CTA.

VariantUse it for
brandThe single most important action on a surface — modal confirm, form submit, page CTA. At most one per page, panel, modal, or form.
outlineStandalone secondary actions — Cancel next to a brand confirm, header and form side actions. The default when unsure.
mutedSame tier as outline, for busy surfaces where an extra border adds noise — inside cards, dense panels, filter/pill rows.
ghostRepeated and contextual actions — toolbars, icon-only buttons, per-row actions in lists/tables, close/dismiss, "more options".
destructiveIrreversible or dangerous actions only — delete, remove, revoke. Usually the confirm of a confirmation dialog.
textInline actions sitting in a line of text — captions, helper rows, footnotes.
linkNavigation-like inline actions — underlines on hover.
tsx
<Button variant="brand">Save changes</Button>
<Button variant="outline">Cancel</Button>
<Button variant="muted">Edit</Button>
<Button variant="ghost">More options</Button>
<Button variant="destructive">Delete</Button>
<Button variant="text">Learn more</Button>
<Button variant="link">View documentation</Button>

Sizes

SizeHeightUse case
xxs20pxCompact UI, tags, tight spaces
xs24pxSecondary actions in dense layouts
sm28pxToolbars, inline actions
md32pxDefault — most buttons in the interface
lg36pxPrimary CTAs, hero sections
tsx
<Button size="xxs">Tag</Button>
<Button size="md">Submit</Button>
<Button size="lg">Get started</Button>

With icons

Use prefix for an icon before the label or suffix for one after. Icons automatically scale to match the button size.

tsx
import { IconPlus, IconArrowRight } from "@rogo-technologies/ui/icons";

<Button prefix={<IconPlus />}>Add item</Button>
<Button suffix={<IconArrowRight />}>Continue</Button>
<Button prefix={<IconPlus />} suffix={<IconArrowRight />}>
  Add and continue
</Button>

Loading

When loading is true, a spinner replaces the prefix icon, the button becomes disabled, and aria-busy is set. Width stays stable to prevent layout shift.

tsx
const [isLoading, setIsLoading] = useState(false);

async function handleSubmit() {
  setIsLoading(true);
  await saveData();
  setIsLoading(false);
}

<Button loading={isLoading} onClick={handleSubmit}>
  Save changes
</Button>;

Disabled

tsx
<Button disabled={!isFormValid}>Submit</Button>
<Button disabled={isLoading}>Save</Button>

Icon only

Always provide an aria-label for accessibility.

SizeDimensions
xxs20×20
xs24×24
sm28×28
md32×32
lg36×36
tsx
<Button iconOnly aria-label="Open settings">
  <IconSettingsGear3 />
</Button>

<Button variant="ghost" iconOnly aria-label="More options">
  <IconMoreHorizontal />
</Button>

Rounded

Pill-shaped buttons. Works with all sizes and variants.

tsx
<Button rounded>Subscribe</Button>

<Button rounded iconOnly aria-label="Add">
  <IconPlus />
</Button>

Hit area

hitArea renders an invisible ghost element around the button that enlarges its pointer target by 4/8/12px per edge (sm/md/lg) without affecting layout. Useful for small buttons (xxs/xs) in sparse surroundings, where the 24px minimum pointer target isn't met by the button itself. The ghost can overlap adjacent elements, so don't use it in dense clusters. See the Checkbox hit area docs for details on the mechanism.

tsx
<Button size="xxs" hitArea="sm">
  Tag
</Button>

As link

Render as a different element via render — e.g. a Next.js Link for navigation.

tsx
import Link from "next/link";

<Button render={<Link href="/dashboard" />}>Go to Dashboard</Button>

<Button render={<a href="https://example.com" target="_blank" />}>
  External link
</Button>

API

PropTypeDefaultDescription
variant"brand" | "outline" | "muted" | "ghost" | "destructive" | "text" | "link""brand"Visual style of the button.
size"xxs" | "xs" | "sm" | "md" | "lg""md"Size of the button.
iconOnlybooleanfalseRenders a square button for icon-only use.
roundedbooleanfalseApplies fully rounded corners (pill shape).
prefixReactNodeElement to render before the label.
suffixReactNodeElement to render after the label.
loadingbooleanfalseShows a spinner and disables the button.
disabledbooleanfalseDisables the button.
renderReactElementRenders as a different element (e.g., Link).
hitArea"sm" | "md" | "lg"Enlarges the pointer target by 4/8/12px per edge via an invisible ghost element.

The Button accepts all standard HTML button attributes.

Guidelines

Do

  • Always pass variant explicitly — the default is brand, and an accidental primary is the most common variant bug
  • Use brand for the primary action on a page or in a modal — at most one per surface
  • Use outline or muted for secondary actions alongside a primary button
  • Use ghost for tertiary, repeated, or contextual actions (toolbars, icon buttons, row actions)
  • Use destructive only for irreversible or dangerous actions
  • Pair modal footers as brand (or destructive) confirm + outline cancel
  • Provide aria-label for icon-only buttons
  • Use loading state for async operations to provide feedback
  • Keep button labels concise and action-oriented ("Save", "Delete", "Continue")

Don't

  • Don't use multiple brand buttons in the same context — there should be one clear primary action; two siblings of equal weight are both outline or both ghost
  • Don't use destructive for non-dangerous actions just for visual emphasis
  • Don't disable buttons without explaining why (consider a tooltip or helper text)
  • Don't use icon-only buttons without aria-label — they're inaccessible to screen readers
  • Don't mix too many button variants in one area — it creates visual noise
  • Don't use text or link variants for important actions — they lack visual prominence
PreviousBadge
Made in NYC© 2026 Rogo Technologies Inc.