Button
Buttons trigger actions. Use the primary style for the main action, others for lower-emphasis actions.
Overview
The Button component 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.
import { Button } from "@rogo-technologies/ui/button"
<Button variant="brand" size="md">Click me</Button>Variants
Use the variant prop to change button emphasis. The default variant is brand.
| Variant | Purpose |
|---|---|
brand | Primary actions—the main call to action on a page or section. |
outline | Secondary actions—bordered style with subtle background. |
muted | Secondary actions—subtle filled background, lower emphasis than outline. |
ghost | Tertiary actions—transparent background, appears on hover. |
destructive | Dangerous actions—delete, remove, or irreversible operations. |
text | Minimal styling—inline actions without visual weight. |
link | Link-style—underlines on hover, for navigation-like actions. |
// Primary action
<Button variant="brand">Save changes</Button>
// Secondary actions
<Button variant="outline">Cancel</Button>
<Button variant="muted">Edit</Button>
// Tertiary action
<Button variant="ghost">More options</Button>
// Dangerous action
<Button variant="destructive">Delete</Button>
// Minimal actions
<Button variant="text">Learn more</Button>
<Button variant="link">View documentation</Button>Sizes
Use the size prop to control button dimensions. The default size is md.
| Size | Height | Use Case |
|---|---|---|
xxs | 20px (h-5) | Compact UI, tags, tight spaces |
xs | 24px (h-6) | Secondary actions in dense layouts |
sm | 28px (h-7) | Toolbars, inline actions |
md | 32px (h-8) | Default—most buttons in the interface |
lg | 36px (h-9) | Primary CTAs, hero sections |
// Compact button for tight spaces
<Button size="xxs">Tag</Button>
// Default size for most use cases
<Button size="md">Submit</Button>
// Large button for primary CTAs
<Button size="lg">Get started</Button>With Icons
Use prefix to add an icon before the label or suffix to add one after. Icons automatically scale to match the button size.
import { IconPlus, IconArrowRight } from "@rogo-technologies/ui/icons"
// Icon before label (common for "Add" actions)
<Button prefix={<IconPlus />}>Add item</Button>
// Icon after label (common for "Next" actions)
<Button suffix={<IconArrowRight />}>Continue</Button>
// Both icons (use sparingly)
<Button prefix={<IconPlus />} suffix={<IconArrowRight />}>
Add and continue
</Button>Loading
Use the loading prop to show a spinner and disable interaction during async operations. The button remains the same width to prevent layout shift.
const [isLoading, setIsLoading] = useState(false)
async function handleSubmit() {
setIsLoading(true)
await saveData()
setIsLoading(false)
}
<Button loading={isLoading} onClick={handleSubmit}>
Save changes
</Button>When loading is true:
- A spinner replaces the prefix icon
- The button becomes disabled
aria-busyis set for screen readers
Disabled
Use the disabled prop to prevent interaction when the action is unavailable.
// Disable until form is valid
<Button disabled={!isFormValid}>Submit</Button>
// Disable during loading (automatic when loading={true})
<Button disabled={isLoading}>Save</Button>Icon Only
Use the iconOnly prop to create square buttons containing only an icon. The button becomes a perfect square based on the size. Always provide an aria-label for accessibility.
| Size | Dimensions |
|---|---|
xxs | 20×20px |
xs | 24×24px |
sm | 28×28px |
md | 32×32px |
lg | 36×36px |
// Icon-only button with accessibility label
<Button iconOnly aria-label="Open settings">
<IconSettingsGear3 />
</Button>
// Different variants work with iconOnly
<Button variant="ghost" iconOnly aria-label="More options">
<IconMoreHorizontal />
</Button>Rounded
Use the rounded prop to create pill-shaped buttons with fully rounded corners. Works with all sizes and variants.
// Pill-shaped button
<Button rounded>Subscribe</Button>
// Rounded icon-only button (circular)
<Button rounded iconOnly aria-label="Add">
<IconPlus />
</Button>As Link
Use the render prop to render the button as a different element, such as a Next.js Link for navigation.
import Link from "next/link"
// Render as Next.js Link
<Button render={<Link href="/dashboard" />}>
Go to Dashboard
</Button>
// With an anchor tag
<Button render={<a href="https://example.com" target="_blank" />}>
External Link
</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
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. |
iconOnly | boolean | false | Renders a square button for icon-only use. |
rounded | boolean | false | Applies fully rounded corners (pill shape). |
prefix | ReactNode | — | Element to render before the label. |
suffix | ReactNode | — | Element to render after the label. |
loading | boolean | false | Shows a spinner and disables the button. |
disabled | boolean | false | Disables the button. |
render | ReactElement | — | Renders as a different element (e.g., Link). |
Additionally, the Button accepts all standard HTML button attributes.
Usage Guidelines
Do
- Use
brandfor the primary action on a page or in a modal - Use
outlineormutedfor secondary actions alongside a primary button - Use
ghostfor tertiary or contextual actions (e.g., in toolbars) - Use
destructiveonly for irreversible or dangerous actions - Provide
aria-labelfor icon-only buttons - Use
loadingstate for async operations to provide feedback - Keep button labels concise and action-oriented ("Save", "Delete", "Continue")
Don't
- Don't use multiple
brandbuttons in the same context—there should be one clear primary action - Don't use
destructivefor 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
textorlinkvariants for important actions—they lack visual prominence