Skip to content

Component · 01

Button

Lifts off the page on hover and presses into it on click, like a stamp. Built on a native button, so keyboard and screen reader behaviour comes for free.

Variants

tsx
<Button variant="primary">Primary</Button>
<Button>Secondary</Button>
<Button variant="ghost">Ghost</Button>

Sizes

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

With an icon

SVGs inside a button are sized to the text and never shrink.

tsx
<Button variant="primary">
  Continue <ArrowIcon />
</Button>

States

Loading keeps focus on the button, so a keyboard user does not lose their place; disabled removes it from the tab order.

tsx
<Button loading variant="primary">Saving</Button>
<Button disabled>Disabled</Button>
<Button disabled variant="ghost">Disabled</Button>

As a link

render swaps the element and keeps its props. Style stays identical.

tsx
<Button render={<a href="https://github.com" />}>
  GitHub
</Button>

Override with Tailwind

All gnoud-ui styles live in a cascade layer, so your utilities win without !important.

tsx
<Button className="w-full rounded-full">Full width, pill</Button>

Props

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost""secondary"Visual weight. Use one primary per screen.
size"sm" | "md" | "lg""md"Height and padding.
loadingbooleanfalseShows a spinner and ignores clicks. Stays focusable (aria-disabled), sets aria-busy.
disabledbooleanfalseNative disabled on a <button>; aria-disabled on a custom element.
renderReactElement-Render another element, e.g. a link, keeping its own props.
typestring"button"Defaults to button so it never submits a form by accident.

All other props of <button> (including ref) are passed through.