Tangible Design System · @tangible/ui 0.2.29 · Interactive version · Markdown

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?


Button

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

<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:


Chip

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

Non-interactive (label / badge)

<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)

<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)

<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.