Button

The primary action control — primary, accent, secondary, and ghost variants in three sizes.

atomsSource
import { Button } from '@elirobinson/react/components/atoms/Button';

Styles: @elirobinson/react/styles/atoms/Button.css — already included when you import @elirobinson/react/styles.css.

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';

export default function Basic() {
  return <Button onClick={() => alert('Shipped.')}>Get started</Button>;
}

When to use it

Use Button for actions — submitting a form, opening a dialog, confirming a step. For navigation, use a real link: an <a> styled as a link is honest about what happens on click, works with middle-click and cmd-click, and needs no JavaScript.

  • primary is the default: ink-solid, one per view is a good ceiling.
  • accent is Miltinson Amber — reserve it for the one action I most want taken.
  • secondary is the bordered workhorse for everything alongside a primary.
  • ghost sits in toolbars and card corners where a border would add noise.

Variants

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';

export default function Variants() {
  return (
    <div className="demo-row">
      <Button variant="primary">Primary</Button>
      <Button variant="accent">Accent</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="ghost">Ghost</Button>
    </div>
  );
}

Sizes

All three sizes keep the 44×44px minimum touch target — the smaller sizes shrink the visible control, not the hit area.

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';

export default function Sizes() {
  return (
    <div className="demo-row">
      <Button size="sm">Small</Button>
      <Button size="md">Medium</Button>
      <Button size="lg">Large</Button>
    </div>
  );
}

Disabled

Show code
import { Button } from '@elirobinson/react/components/atoms/Button';

export default function States() {
  return (
    <div className="demo-row">
      <Button disabled>Disabled</Button>
      <Button variant="secondary" disabled>
        Disabled secondary
      </Button>
    </div>
  );
}

Props

PropTypeDefaultDescription
size"sm" | "md" | "lg"md
variant"primary" | "accent" | "secondary" | "ghost"primary

Also accepts all ButtonHTMLAttributes<HTMLButtonElement> props.

Accessibility

  • Renders a native <button> with type="button" by default, so a button inside a form never submits it by accident — pass type="submit" when submitting is the point.
  • Keyboard: Tab focuses, Enter and Space activate. That contract comes from the native element; nothing re-implements it.
  • Focus is marked with the system's high-contrast ink ring (:focus-visible), never removed.
  • The ref forwards to the underlying <button> element, so focus management from a parent (ref.current.focus()) works directly.
  • Icon-only buttons need an aria-label — the component doesn't invent one.

Do

  • Use one primary or accent button per view — hierarchy is the point.
  • Write button labels as verbs: "Save changes", not "Changes".
  • Pass type="submit" explicitly inside forms when submitting is intended.
  • Give icon-only buttons an aria-label.

Don't

  • Use a Button for navigation — style a link instead.
  • Disable a submit button to signal a validation error — show the error and keep it clickable.
  • Stack multiple accent buttons in one section; amber is a signal, not a fill.
  • Shrink the hit area below 44×44px — density comes from the visible control, not the target.