MiHCM
primitives/@mihcm/ui·v0.21.0·stable

Button

Primary action affordance. Seven variants, six sizes, icon slots, rounded or hard-edge shapes, and tokenized Tailwind class overrides. Universal across web and native.

In context

A realistic showcase — page-header CTAs, form actions, semantic tonal overrides, and a hard-edge toolbar with the loading state.

Payroll runs

March 2026 cycle — 142 employees

On track

Page-header pattern: one primary action, a secondary outline, a ghost background action, and icon-only chrome on the right.

Invite teammate

Dialog-footer pattern — cancel (ghost) + submit (primary).

Email
jordan.diaz@mihcm.com
Role
People Operations Lead

Default

import { Button, IconButton } from '@mihcm/ui/Button';
 
<Button>Save changes</Button>

Destructive confirmation

For actions that destroy data — pair with a confirm dialog.

<Button variant="destructive" onClick={handleDelete}>
  Delete account
</Button>

With leading icon

import { Button } from '@mihcm/ui/Button';
import { Plus } from '@mihcm/icons';
 
<Button leadingIcon={<Plus className="size-4" />}>
  New project
</Button>

With icon options

Use leadingIcon and trailingIcon for labelled actions. Use size="icon" only when the icon is the whole affordance and provide an accessible label.

import { ArrowRight, Plus, Search } from '@mihcm/icons';
 
<Button leadingIcon={<Plus className="size-4" />}>Create</Button>
 
<Button variant="outline" trailingIcon={<ArrowRight className="size-4" />}>
  Continue
</Button>
 
<IconButton aria-label="Search">
  <Search className="size-4" />
</IconButton>

Icon only

Use IconButton for icon-only actions. It always renders size="icon" and requires either aria-label or accessibilityLabel.

import { IconButton } from '@mihcm/ui/Button';
import { Search, Settings } from '@mihcm/icons';
 
<IconButton aria-label="Search">
  <Search />
</IconButton>
 
<IconButton shape="hard" variant="ghost" aria-label="Settings">
  <Settings />
</IconButton>

Loading state

isLoading sets aria-busy and disables interaction without changing the layout.

<Button isLoading>Saving…</Button>

Form button types

Button defaults to type="button" so toolbar and dialog actions do not accidentally submit nearby forms. Set type="submit" only for the submit action.

<Button type="submit">Save payroll run</Button>
<Button type="reset" variant="outline">Reset form</Button>
<Button type="button" variant="ghost">Open help</Button>

Sizes

<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">XL</Button>
<Button size="xxl">XXL</Button>

Hard edge

Use shape="hard" for dense enterprise toolbars, grid controls, and edge-aligned page actions where radius should be removed.

<Button shape="hard">Hard primary</Button>
<Button shape="hard" variant="outline">Hard outline</Button>

Tailwind class overrides

Button variants are the baseline, not the limit. Use className for semantic Tailwind token utilities when a workflow needs success, warning, destructive, or other system tones. Classes are merged after the variant with tailwind-merge, so border-success replaces the outline variant's default border class.

Avoid raw hex values, arbitrary bracket utilities, inline styles, or local CSS modules. Keep overrides in the MiHCM token/Tailwind surface so light mode, dark mode, focus states, and MCP enforcement stay consistent.

<Button
  variant="outline"
  className="border-success text-success hover:bg-success/10 focus-visible:ring-success"
>
  Approve
</Button>
 
<Button
  variant="outline"
  className="border-warning text-warning hover:bg-warning/10 focus-visible:ring-warning"
>
  Review
</Button>
 
<Button
  variant="outline"
  className="border-destructive text-destructive hover:bg-destructive/10 focus-visible:ring-destructive"
>
  Escalate
</Button>

All variants together

<div className="flex flex-wrap gap-2">
  <Button variant="default">Default</Button>
  <Button variant="accent">Accent</Button>
  <Button variant="destructive">Destructive</Button>
  <Button variant="outline">Outline</Button>
  <Button variant="secondary">Secondary</Button>
  <Button variant="ghost">Ghost</Button>
  <Button variant="link">Link</Button>
</div>