Chips
components specs/components/chips.kmd
Compact element representing an entity, attribute, or action — smaller than a button and used in groups. Material parity (`/components/chips`). Covers four canonical variants (assist, filter, input, suggestion) and their behaviors.
Quando esta spec se aplica
Triggers primários
- Add a chip
Todos os triggers
- Show a removable tag or attribute
- Offer multi-select filters in a horizontal row
- Suggest text snippets for quick reply
- Trigger contextual actions tied to a noun
Corpo da especificação
Spec — Chips
Facet Visual of Koder Design. Material parity: https://m3.material.io/components/chips.
4 variants
| Variant | Purpose | Selectable | Removable |
|---|---|---|---|
| Assist | Trigger contextual action tied to a noun ("Add to calendar") | No | No |
| Filter | Toggle inclusion in a filtered set | Yes (multi-select) | No |
| Input | Represent user-entered value (email tag, applied filter) | No | Yes (× button) |
| Suggestion | Predefined response or query option | One-shot tap | No |
Pick variant by question: "Does this represent a thing I typed?" → input. "Does this filter a list?" → filter. "Does this give me a shortcut to type something?" → suggestion. "Does this trigger an action attached to nearby content?" → assist.
Anatomy
┌──────────────────┐ ┌──────────────────┐
│ ⚙ Settings │ │ ● Important × │
└──────────────────┘ └──────────────────┘
↑ ↑ ↑ ↑ ↑
icon label leading label remove
(optional) (input only)
- Height: 32 px (default)
- Padding: 12 px horizontal (label only) / 8 px (with icon)
- Corner radius: 8 px (Material 3 default, see preset variation)
- Label:
label-large(14/20, weight 500) - Leading icon: 18 px, optional
- Trailing: × icon (input variant) or check (selected filter)
- Hit target: minimum 48 × 48 px (extends invisibly around chip)
- Container bg: variant-specific (see R2)
R1 — Group layout
Chips appear in groups. Layout rules:
| Layout | When |
|---|---|
| Horizontal scroll | Mobile / narrow surface, many chips |
| Wrap | Default — chips wrap to next line when overflow |
| Single row | Few chips (≤ 5) that always fit |
Spacing between chips: 8 px horizontal, 8 px vertical.
R2 — Visual by variant + state
| Variant | Rest bg | Rest border | Selected bg | Selected border |
|---|---|---|---|---|
| Assist | transparent | 1 px outline | n/a | n/a |
| Filter (unselected) | transparent | 1 px outline | secondary-container | none |
| Filter (selected) | secondary-container | none | (same) | none |
| Input | surface-container-low | 1 px outline-variant | n/a | n/a |
| Suggestion | transparent | 1 px outline | (one-shot tap, no selected state) | n/a |
Elevation: 0 dp at rest; rises to 2 dp on hover (Material 3 "elevated" chip is an opt-in variant — document explicitly if used).
R3 — Filter chip selection
| Action | Result |
|---|---|
| Tap unselected | Becomes selected (add filter) |
| Tap selected | Becomes unselected (remove filter) |
| Long-press (touch) | Show tooltip with full label |
Filter chips are multi-select by default — multiple can be selected simultaneously. If single-select needed (mutually exclusive), use radio buttons or segmented buttons instead.
Selection state shows:
- Leading check icon (✓) replaces optional leading icon
- Background fills with
secondary-container - Border removed (filled state)
R4 — Input chip removal
× icon on right side, 18 px, accessible via:
- Tap × → remove chip + announce "Removed: [label]" to screen reader
- Backspace when chip has keyboard focus → remove
- Backspace in adjacent text field → focus last chip
- Keyboard delete on focused chip → remove + move focus to previous
Animation: chip fade-out (motion-fast) + adjacent chips slide to fill.
R5 — States (all variants)
| State | Visual change |
|---|---|
| Rest | Base style |
| Hover | State layer 8% over base |
| Focused | 2 px focus ring outside chip border |
| Pressed | State layer 12% |
| Disabled | 38% opacity, no interaction |
R6 — With icon
Leading icon slot accepts:
- 18 px icon (default — matches text height)
- 24 px avatar (input chip representing a person)
When icon is present:
- Padding-left reduces from 12 px → 8 px
- Icon-to-label gap: 4 px
Selected filter chip ALWAYS shows check leading; replaces optional icon (don't try to show both — order is check OR icon).
R7 — Accessibility
- Assist:
role="button"+ accessible name from label - Filter:
role="checkbox"(multi) ORrole="radio"(single, rare) witharia-checkedstate - Input:
role="button"for chip + nestedrole="button"for × remove; remove button hasaria-label="Remove [label]" - Suggestion:
role="button" - Group container:
role="group"+aria-labeldescribing the collection - Keyboard:
- Tab: enters first chip in group, then Tab moves OUT
- Arrow Left/Right: moves between chips within group
- Space / Enter: toggles (filter) or activates (assist / suggestion)
- Backspace / Delete: removes (input)
R8 — Density
| Density | Height | Padding | Icon size |
|---|---|---|---|
| Compact | 28 px | 10 px | 16 px |
| Default | 32 px | 12 px | 18 px |
| Comfortable | 40 px | 16 px | 20 px |
Inherits from customization.kmd.
R9 — Per-preset variation
| Preset | Corners | Selected style |
|---|---|---|
material3 | 8 px radius | Filled tonal container |
material2 | 16 px pill | Saturated accent, white text |
ios_cupertino | 16 px pill | Filled accent |
gnome | 6 px radius | Solid accent border, tonal bg |
windows_11 | 4 px radius | Accent color filled, subtle outline |
brutalist | 0 px (sharp) | Inverted colors, 2 px border |
terminal_classic | Bracketed text [Filter] / [X] | Asterisk prefix *[Filter] |
R10 — Forbidden patterns
- ❌ Chips taller than 48 px (becomes a button; use button instead)
- ❌ Chips with multi-line labels (truncate or use card / list)
- ❌ Mixing variants in a single group (a row of filter chips with one input chip in the middle is confusing)
- ❌ Filter chip groups acting as single-select (use radio / segmented buttons)
- ❌ Chip without label (icon-only — use icon button)
- ❌ Long-press as the only way to remove an input chip (no discoverability)
- ❌ Animating bg color on selection without a state layer (jarring flash)
- ❌ Hit target < 48 × 48 px
Cross-link
interaction/selection.kmd— multi-select patterninteraction/states.kmd— hover / pressed / focused layersthemes/color-roles.kmd—secondary-containerfor selected filterthemes/typography.kmd—label-largecomponents/buttons.kmd— single primary action siblingcomponents/text-fields.kmd— input chip parent contextfoundations/elements.kmd— Control + Marker families
Requirements (testable)
Requirement: Filter chip multi-select toggle {#req-chips-filter-toggle}
A filter chip SHALL toggle its own selection independently on each tap — tapping an unselected chip adds it to the filtered set and tapping a selected chip removes it — and multiple filter chips within the same group SHALL be selectable simultaneously (multi-select by default). A selected filter chip SHALL render with a secondary-container background, no border, and a leading check icon replacing any optional leading icon.
Scenario: Tapping an unselected filter chip selects it
- GIVEN a group of filter chips where the chip labeled "Important" is unselected
- WHEN the user taps the "Important" chip
- THEN the chip becomes selected
- AND its background fills with
secondary-container - AND its border is removed
- AND a leading check icon (✓) is shown in place of any optional leading icon
Scenario: Tapping a selected filter chip deselects it
- GIVEN a filter chip labeled "Important" that is currently selected
- WHEN the user taps the "Important" chip
- THEN the chip becomes unselected
- AND it reverts to a transparent background with a 1 px
outlineborder
Scenario: Multiple filter chips selected at once
- GIVEN a filter chip group with chips "A", "B", and "C" all unselected
- WHEN the user taps "A" and then taps "C"
- THEN both "A" and "C" are selected simultaneously
- AND "B" remains unselected
Requirement: Input chip removal {#req-chips-input-removal}
An input chip SHALL be removable via its trailing × button and via keyboard, and removal SHALL announce "Removed: [label]" to the screen reader. Tapping the × or pressing Backspace/Delete while the chip has keyboard focus SHALL remove the chip; pressing Backspace in an adjacent text field SHALL move focus to the last chip; removing a focused chip via keyboard SHALL move focus to the previous chip.
Scenario: Removing an input chip by tapping the × button
- GIVEN an input chip labeled "user@example.com" with a trailing × button
- WHEN the user taps the × button
- THEN the chip is removed from the group
- AND the screen reader announces "Removed: user@example.com"
Scenario: Removing a focused input chip with the keyboard
- GIVEN an input chip that currently holds keyboard focus
- WHEN the user presses Delete (or Backspace)
- THEN the chip is removed
- AND keyboard focus moves to the previous chip
Scenario: Backspace in adjacent text field focuses the last chip
- GIVEN an input chip group with a trailing text field that holds focus and is empty
- WHEN the user presses Backspace in the text field
- THEN keyboard focus moves to the last chip in the group
Requirement: Keyboard navigation and roles by variant {#req-chips-a11y-keyboard}
Chips SHALL expose variant-appropriate ARIA roles — assist and suggestion as role="button", filter as role="checkbox" (or role="radio" when single-select) with an aria-checked state, and the input remove button with aria-label="Remove [label]" — and the group container SHALL use role="group" with a descriptive aria-label. Keyboard interaction SHALL follow: Tab enters the first chip and then moves out of the group, Arrow Left/Right moves between chips within the group, and Space/Enter toggles a filter chip or activates an assist/suggestion chip.
Scenario: Arrow keys move between chips within a group
- GIVEN a chip group with
role="group"and three chips, the first chip focused - WHEN the user presses Arrow Right
- THEN keyboard focus moves to the second chip in the group
Scenario: Filter chip exposes checkbox role and reflects state
- GIVEN a multi-select filter chip rendered with
role="checkbox"andaria-checked="false" - WHEN the user presses Space while the chip is focused
- THEN the chip becomes selected
- AND its
aria-checkedattribute becomestrue
Requirement: Interaction state layers {#req-chips-states}
Chips SHALL render distinct visual states across all variants: a hover state applying an 8% state layer over the base, a focused state showing a 2 px focus ring outside the chip border, a pressed state applying a 12% state layer, and a disabled state at 38% opacity that blocks all interaction.
Scenario: Disabled chip ignores taps
- GIVEN a chip rendered in the disabled state at 38% opacity
- WHEN the user taps the chip
- THEN no selection or activation occurs
- AND the chip does not change state
Scenario: Focused chip shows a focus ring
- GIVEN a chip that is not focused
- WHEN the chip receives keyboard focus
- THEN a 2 px focus ring is drawn outside the chip border
Requirement: Hit target and shape constraints {#req-chips-forbidden}
A chip SHALL provide a minimum interactive hit target of 48 × 48 px (extending invisibly around the visual chip), SHALL always carry a text label, and SHALL NOT exceed 48 px in height nor render a multi-line label.
Scenario: Small chip still exposes a 48 px hit target
- GIVEN a compact-density chip whose visual height is 28 px
- WHEN the interactive hit target is measured
- THEN the hit target is at least 48 × 48 px
Scenario: Icon-only chip is rejected
- GIVEN a chip configured with a leading icon and no text label
- WHEN the chip is validated against the spec
- THEN it is rejected as a forbidden icon-only chip
- AND an icon button is indicated as the correct element instead
Referências
specs/foundations/elements.kmdspecs/themes/color-roles.kmdspecs/themes/typography.kmdspecs/interaction/selection.kmdspecs/interaction/states.kmd