> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Button Usage Standards

> Version: 1.0.0 Last Updated: 2026-03-13 Scope: All Button usage from @/shared/ui/button

**Version:** 1.0.0\
**Last Updated:** 2026-03-13\
**Scope:** All `Button` usage from `@/shared/ui/button`

***

## Import

Use the shared Button component only:

```tsx theme={null}
import { Button } from '@/shared/ui/button';
```

Do not use legacy paths (e.g. `@/components/ui/button`).

***

## Variants and Sizes

**Authority:** Variant and size API and usage guidance are defined in [src/shared/ui/button.tsx](../../src/shared/ui/button.tsx). Summary:

| Variant       | Use for                                                                  |
| ------------- | ------------------------------------------------------------------------ |
| `default`     | Primary CTAs, form submit buttons                                        |
| `destructive` | Delete, reject, and other dangerous actions                              |
| `outline`     | Secondary actions, toolbar buttons                                       |
| `secondary`   | Tertiary or muted actions                                                |
| `ghost`       | Icon buttons, toolbars, minimal chrome                                   |
| `link`        | Inline navigation, text-style links                                      |
| `success`     | Approve, complete, positive confirmation                                 |
| `warning`     | Caution actions, escalation, review needed                               |
| `soft`        | Subtle emphasis, dashboard quick actions (same semantic as Badge `info`) |

| Size      | Use for                                                          |
| --------- | ---------------------------------------------------------------- |
| `default` | Standard buttons (h-10)                                          |
| `sm`      | Compact buttons in toolbars (h-9)                                |
| `xs`      | Very compact: table row actions, inline (h-7)                    |
| `lg`      | Hero CTAs, prominent actions (h-11)                              |
| `icon`    | Icon-only buttons; 44px min touch target (use with `aria-label`) |

**Semantic consistency:** Use `destructive` for delete/reject actions, `success` for approve/complete actions, and `warning` for caution. Prefer the `loading` prop for async submit actions (see [Loading State](#loading-state)).

***

## Icon-Only Buttons (Accessibility)

Icon-only buttons **must** have an `aria-label` so screen readers can announce the action.

```tsx theme={null}
// ✅ CORRECT
<Button variant="ghost" size="icon" aria-label="Edit item" onClick={onEdit}>
  <Pencil className="h-4 w-4" aria-hidden="true" />
</Button>
<Button variant="ghost" size="icon" aria-label="Go back" onClick={onBack}>
  <ArrowLeft className="h-4 w-4" aria-hidden="true" />
</Button>

// ❌ WRONG: No accessible name
<Button variant="ghost" size="icon" onClick={onEdit}>
  <Pencil className="h-4 w-4" />
</Button>
```

When the icon is decorative (button has visible text), use `aria-hidden="true"` on the icon.

***

## Loading State

Use the Button `loading` prop for submit and other async actions so the button shows a spinner and is disabled automatically.

```tsx theme={null}
// ✅ CORRECT
<Button type="submit" loading={isPending}>Save</Button>
<Button onClick={handleDelete} variant="destructive" loading={deleteMutation.isPending}>Delete</Button>

// ❌ AVOID: Manual disabled without built-in spinner
<Button type="submit" disabled={isPending}>Save</Button>
```

***

## asChild with Link

When using `asChild` with `Link`, the link must provide the accessible name (visible text or `aria-label`).

```tsx theme={null}
// ✅ CORRECT
<Button variant="ghost" size="icon" asChild>
  <Link to="/charges" aria-label="Back to charges">
    <ArrowLeft className="h-4 w-4" aria-hidden="true" />
  </Link>
</Button>

// ✅ CORRECT: Visible text
<Button variant="outline" asChild>
  <Link to="/dashboard">Go to dashboard</Link>
</Button>
```

***

## Dialog Footer Order

In `DialogFooter`, place **Cancel (or secondary) on the left**, **primary action on the right**.

```tsx theme={null}
<DialogFooter>
  <Button variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
  <Button type="submit" loading={isPending}>Save</Button>
</DialogFooter>
```

***

## References

* [src/shared/ui/button.tsx](../../src/shared/ui/button.tsx) — Component and variant/size API
* [ICON\_GUIDE.md](ICON_GUIDE.md) — Icon sizing and accessibility
* [UI\_UX\_STANDARDS.md](UI_UX_STANDARDS.md) — Semantic tokens and design system
* [.cursor/rules/dialog-size-standards.md](../../.cursor/rules/dialog-size-standards.md) — Dialog and sheet sizes
