# Chip vs Button

Both components can look identical at small sizes and in ghost or outline variants. The difference is not visual — it is semantic. Choosing the wrong one produces the wrong ARIA contract and incorrect screen reader announcements.

---

## The decision rule

**Is this an action the user performs, or a label/tag/toggle representing a value?**

- **Action** (save, delete, submit, navigate, open a modal) → use **Button**
- **Label or tag** (category, status badge, read-only value) → use **Chip** (non-interactive)
- **Filter toggle or multi-select token** (is this category active?) → use **Chip** (interactive or inside **ChipGroup**)

---

## Button

Use `Button` when the element triggers an action. It always carries action intent — something happens when you activate it.

```tsx
<Button label="Save Changes" />
<Button label="Delete" theme="danger" leftIconName="system/trash" />
<Button label="Open settings" variant="ghost" onClick={openSettings} />
```

**ARIA pattern:** Native `<button>` element. Screen reader announces: *"Save Changes, button"*.

**Good use cases:**

- Form submit / save / cancel
- Delete, archive, publish
- Open a modal, drawer, or popover
- Navigation links (`href` renders as `<a>` with Button styling)

---

## Chip

Use `Chip` when the element represents a value, category, or status — not an action.

### Non-interactive (label / badge)

```tsx
<Chip theme="success">Published</Chip>
<Chip theme="warning">Pending Review</Chip>
<Chip theme="secondary">Design</Chip>
```

No role, no tabIndex. Pure display — the value is present or it isn't.

### Interactive (filter toggle)

```tsx
<Chip interactive onClick={toggle} selected={active}>
  Design
</Chip>
```

**ARIA pattern:** Gets `role="button"` and `aria-pressed`. Screen reader announces: *"Design, button, pressed"* / *"not pressed"*. The question answered is "is this category currently on or off?" — not "what action does this trigger?"

### Filter group (ChipGroup)

```tsx
<ChipGroup value={activeFilter} onValueChange={setFilter}>
  <Chip value="all">All</Chip>
  <Chip value="active">Active</Chip>
  <Chip value="done">Done</Chip>
</ChipGroup>
```

`ChipGroup` manages selection state, keyboard navigation, and `aria-pressed` across the set. Each chip represents membership in a category.

---

## Side-by-side comparison

| Aspect | Button | Chip |
| - | - | - |
| **Intent** | Action — something happens | State — this value is present/selected |
| **ARIA pattern** | Native `<button>` | `<span role="button" aria-pressed>` (when interactive) |
| **Size scale** | `sm` / `md` / `lg` (control heights) | `xs` / `sm` / `md` (compact, inline) |
| **Loading state** | Yes | No |
| **Group management** | No | Yes — ChipGroup |
| **Screen reader** | "Save, button" | "Design, button, not pressed" |

---

## Why the visual overlap exists

Chips and Buttons share the same visual vocabulary — border radius, padding scale, icon placement — because the *appearance* of a small pressable element should be consistent regardless of its semantic role. A ghost-styled element could be either a low-emphasis action (Button) or a filter token (Chip).

The visual similarity is intentional. The semantic difference is what must be decided correctly.

---

## Common mistakes

**Using a small Button as a filter pill.** If you have "All / Active / Completed" toggles above a list, those are filters — use `Chip` inside `ChipGroup`. Using `Button` here misrepresents the state (no `aria-pressed`), loses the group's keyboard navigation, and announces "button" when "button, pressed/not pressed" is correct.

**Using an interactive Chip for a primary CTA.** "Save Changes" is an action — always use `Button`. A Chip CTA gets `aria-pressed` semantics, which implies a toggle, not an action. Screen readers will announce it as pressed/not pressed rather than a simple action trigger.

**Choosing based on visual size.** `Button size="sm"` and `Chip size="md"` can look nearly identical. The choice is never about which looks right — it is always about whether the element triggers an action or represents a value.

---

Interactive version: https://storybook-tangible-ui.pages.dev/?path=/docs/guides-chip-vs-button--docs
