> ## Oymyakon DS index
> Fetch the full index at: https://super-dollop-pzmo65r.pages.github.io/llms.txt
> HTML preview: https://super-dollop-pzmo65r.pages.github.io/chips-action.html
> Source: specs/components/chips-action/chips-action.md, specs/components/chips-action/chips-action-a11y.md, specs/components/chips-action/capabilities.json

---

# ChipsAction · Oymyakon DS 3

> A compact pill-shaped button for a quick action: it opens an input — a sheet or a modal — and
> then shows the chosen value, or fills a field with a ready-made value in one tap.

**Version:** 3.1.5 · **Status:** Ready · **Figma:** `[ChipsAction] 3.1` (main components file `7vdl5YkZFDWvh9QvSmydsH`, page `6388:540`; sets `M-ChipsAction` `10997:5719` (key `b99e0481…`) and `S-ChipsAction` `22962:21969` (key `22777fb2…`); private slot sets `.↳🔴Slot#1` `10086:29717` and `.↳🔵Slot#2` `10086:29850`; press staging `.ChipsItemPressedAnimation` `10318:22084`; Specification frame `6390:17466` (the 3.0 Chips spec); update frame `Update 3.1` `22838:14180`)

---

## 1. Description

ChipsAction is a pill-shaped button that holds a short title — or only an icon — and runs one action
on tap. It is used on its own or in a row of chips for quick value input (Figma `Update 3.1`):

- **Action** — the chip opens an additional input interface, a bottom sheet or a modal; once the value
  is entered there, the chip shows it in place of its title ("Schedule delivery" → "20 November,
  09:00 AM", the Figma usage example). A chevron in the end slot says
  that the chip opens something.
- **Suggest** — the chip offers a ready-made value for a text field ("I'm here", "Where are you?",
  a standard cargo weight); a tap fills the field, so there is less to type.

ChipsAction is not selectable: it has no Active state and no selection binding. Choosing one or
several options from a set is [ChipsChoice](https://super-dollop-pzmo65r.pages.github.io/chips-choice.md) — the other half of the
3.1 split (Figma `[ChipsChoice] 3.0`, "Rename ChipsItem to ChipsChoice").

The 3.1 update also changed the Standard fill from `Surface/OnGrey` to `Background/Primary` for both
ChipsAction and ChipsChoice.

### Platform implementations

| Platform | Entry point | Version | Notes |
|---|---|---|---|
| iOS | `DsChipsAction` (DS3) | Figma 3.1 | `init(size:title:)` with `DsChipsChoiceSize.m` / `.s`; `subtitle`, `counterValue(Int?)`, `indicatorType(DsIndicatorType?)`, `leadingSlot { }` / `trailingSlot { }`, `.disabled(true)`, `.isLoading(true)`; icon-only = an empty title and a `leadingSlot` (manifest bindings) |
| Android | `DsChip.Action` (`core.compose.ds.v3.chip`) | Figma 3.1 | `size = DsChip.Size.M` / `.S`; `title: DsString?` (null = icon-only), `subtitle`, `counter: Long?`, `indicator: DsChip.Indicator?` (null value = a dot), `startSlot` / `endSlot` take `DsChip.Slot.Icon` / `.Indicator` / `.Avatar`; `enabled`; Skeleton is ambient through `DsSkeletonState` (manifest bindings) |
| Flutter | — | — | Not shipped |
| Web | `src/shared/shared.css` (`.chips-action`) | 3.1.0 | Reference implementation, this repo; preview page `src/chips-action.njk` |

On both platforms the chips also live inside a chips area (`DsChipsArea` / `DsChipArea`, Figma
`[ChipsArea] 3.0`) that lays a row out and forces one size onto every chip — on the web the
[ChipsArea](https://super-dollop-pzmo65r.pages.github.io/chips-area.md), whose Suggest preset is a row of ChipsAction chips. The
area is not part of this spec.

---

## 2. Anatomy

```
ChipsAction (.chips-action)                     button · hug × min s48 (M) / s40 (S) · min width s64
├── Content (.chips-action__content)            the row that scales on press · gap s0
│   ├── Start slot (.chips-action__slot--start)     optional · s24 · Icon / Number Indicator
│   ├── Text container (.chips-action__text)        one column · s4 left / right padding · absent in Icon
│   │   ├── Line (.chips-action__line)              gap s4
│   │   │   ├── Title (.chips-action__title)        Main Body · one line
│   │   │   └── Counter (.chips-action__counter)    optional · Main Body · TextAndIcon/Secondary
│   │   └── Subtitle (.chips-action__subtitle)      optional · Caption
│   └── End slot (.chips-action__slot--end)         optional · s24 · Icon / Number Indicator / Chevron / Delete
└── Indicator (.indicator.chips-action__indicator)  optional · Simple L s12 · top end corner
```

| Part | Required | Description |
|---|---|---|
| **Container** | Required | A pill: hugs its content, minimum width `s64`, minimum height `s48` (M) / `s40` (S), padding `s12` at the start and end, radius full, a `s2` inside border. The whole container is the tap target |
| **Content** | Required | The row of the slots and the text, centred in the container. On press it scales as one piece; the container and the Indicator stay still. The Figma press staging (`.ChipsItemPressedAnimation`) scales this inner row as one frame — the web names it `__content` |
| **Start slot** | Optional (on in Icon type) | Figma `🔴Slot#1`, a `s24` box, content centred: an icon (any DS icon, s24) or a [Number Indicator](https://super-dollop-pzmo65r.pages.github.io/indicator.md) L. Figma also offers an Avatar — no web build of Avatar exists |
| **Text container** | Icon + Title type | Figma `TextContainer`: ONE container holding the Title line (Title + Counter) and the Subtitle as a centred column — `s4` padding left and right, `s0` top and bottom, `s0` between the two lines. Its side padding is the gap between the text and a slot or the chip's edge |
| **Title** | Required in the text | One line in `Body/Main Body`. The chip hugs it — no truncation in Figma; the web keeps it on one line |
| **Counter** | Optional, off | Figma `Counter`: a number after the title, `s4` from it, in `Body/Main Body` and `TextAndIcon/Secondary` — "Breakfast 12" |
| **Subtitle** | Optional, off | A second line under the title, in `Caption/Caption`. With a subtitle the text is two lines (20 + 16 = 36), still inside the s40 / s48 container |
| **End slot** | Optional, off | Figma `🔵Slot#2`, a `s24` box: an icon, a Number Indicator L, the **Chevron** ("chevron-down" — the chip opens a choice) or the **Delete** icon ("close-small" — the tap removes the value). Figma also offers an Avatar (no web build) |
| **Indicator** | Optional, off | An [Indicator](https://super-dollop-pzmo65r.pages.github.io/indicator.md) Simple L (`s12` dot), absolutely positioned on the container's top end corner (top right in LTR). It does not take part in the layout, and it does not move on press |

- The two slots and the text are optional, but a chip always shows an icon or a title: Figma's two
  Chip Types are **Icon** (the start slot alone) and **Icon + Title** (the title with the slots
  optional — off by default).
- The Delete icon is a cue, not a second button: the whole chip is one target, and its one action is
  the removal.

### RTL layout

`RTL = true` mirrors the row: the start slot goes to the right edge, the end slot to the left, the
Counter to the left of the Title, and the Indicator to the top left corner. "chevron-down",
"close-small" and the heart icon are symmetric and do not flip. On the web the root's direction
(`dir="rtl"` on it or an ancestor) mirrors the row and moves the Indicator (`inset-inline-end`).

---

## 3. Variants and sizes

Two sizes, published in Figma as two component sets — the web presets.

| Axis | Values | Default | Web mechanism |
|---|---|---|---|
| **Size** (preset) | `m` · `s` | `m` | The bare `.chips-action` is M (min height `s48`); `.chips-action--s` is S (min height `s40`). `data-ds-preset="m"` / `"s"` |
| **Chip Type** | `icon-title` · `icon` | `icon-title` (Figma Icon+Title) | `.chips-action--icon` with the start slot alone and no `.chips-action__text`; the button then takes an `aria-label`. The modifier sets the Skeleton width (`s64`) |
| **State** | `standard` · `disabled` · `skeleton` | `standard` (Figma Default) | `disabled` on the `<button>` (`aria-disabled="true"` renders the same — a disabled ChipsArea uses it); `.chips-action--skeleton` |
| **Start slot** | `false` · `true` | `false` (`true` in Icon) | The `.chips-action__slot--start` element |
| **Counter** | `false` · `true` | `false` | The `.chips-action__counter` element |
| **Subtitle** | `false` · `true` | `false` | The `.chips-action__subtitle` element |
| **End slot** | `false` · `true` | `false` | The `.chips-action__slot--end` element |
| **Indicator** | `false` · `true` | `false` | The `.indicator.indicator--simple.indicator--l.chips-action__indicator` element |
| **RTL** | `false` · `true` | `false` | `dir="rtl"` on the root or an ancestor |

M and S differ only in the minimum height. Paddings, radius, border, slots and text styles are the
same in both.

---

## 4. States

| State | What shows |
|---|---|
| **Standard** | The content in `TextAndIcon/Primary` (the Counter in `TextAndIcon/Secondary`) on `Background/Primary`, a `Border/Default` border |
| **Disabled** | Every content colour — slot icons, Title, Counter, Subtitle — in `TextAndIcon/Disabled`; the fill and the border unchanged; no Indicator (the Figma Disabled variants carry none); no press, no action |
| **Skeleton** | An empty pill — no slots, no text, no border — `s64` wide in Icon, `s124` in Icon + Title, at the size's height, in `Skeleton/OnWhite` with the DS shimmer |

Interaction on the Standard chip, not on the State axis (the Specification frame's
"Rest · Hover/Pressed · Focus (only Web)" columns):

| Interaction | What shows |
|---|---|
| **Hover** (web, pointer) | The DS pressed overlay (`--shadow-pressed`) over the fill — Figma draws Hover and Pressed as one column |
| **Pressed** | The same overlay, and the content scales to 95% (`pushButton`). The pill keeps its size; the Indicator does not move |
| **Focused** (web) | The border turns `Border/Inform` |

- The Figma frame calls the first state "Default"; the DS name is **Standard**.
- A disabled chip keeps its place and its fill — a row of chips never reflows when one is disabled.

---

## 5. Animation and behavior

Reference: [`motion-rules.md`](https://super-dollop-pzmo65r.pages.github.io/motion.md).

| Event | Pattern | Token | Notes |
|---|---|---|---|
| Press | `pushButton` | `var(--component-push-button-press)` | The content scales 100% → 95% and the pressed overlay comes in, together. The container's shape and the Indicator stay still (Specification frame, "Animation") |
| Release | `pushButton` | `var(--component-push-button-release)` | 95% → 100%, the overlay out |
| Hover in / out (web) | `pushButton` | `var(--component-push-button-release)` | The overlay alone, no scale |
| Focus (web) | `pushButton` | `var(--component-push-button-release)` | The ring colour eases with the overlay — both are one `box-shadow`, so they share its transition |
| Skeleton shimmer | `Patterns/Shimmer` | `var(--pattern-shimmer)` | The DS sweep across the pill; reversed in RTL |
| Value shown after the input | — | — | The host replaces the title; the chip re-hugs its width in the same frame — no width tween |
| Skeleton → content | — | — | The host swaps the skeleton for the chip; no transition of its own |

- A disabled chip and a Skeleton do not react to hover or press.
- Reduced motion: `--component-push-button-*` and `--pattern-shimmer` are zeroed at the token — the
  overlay and the 95% scale apply at once, with no transition, and the skeleton holds still. No
  override of its own.

---

## 6. Color tokens

| Element | Token | Notes |
|---|---|---|
| Fill | `var(--background-primary)` | `--chips-action-fill`. A default — an instance may re-point it to any DS colour (Specification frame: "You may use any color from the DS"). Was `Surface/OnGrey` before 3.1 |
| Border | `var(--border-default)` | `--chips-action-border`. A default, as the fill |
| Slot icons | `var(--text-and-icon-primary)` | `currentColor` from the root. A default |
| Title | `var(--text-and-icon-primary)` | Inherits the root colour. A default |
| Counter | `var(--text-and-icon-secondary)` | Its own colour. A default |
| Subtitle | `var(--text-and-icon-primary)` | Inherits the root colour. A default |
| Disabled content | `var(--text-and-icon-disabled)` | Slot icons, Title, Counter and Subtitle |
| Indicator | `var(--accent-red2)` | The Indicator's own colour contract |
| Number Indicator in a slot | `var(--accent-red2)` | The Indicator's own colour — see the flag below |
| Pressed / hover overlay | `var(--shadow-pressed)` | Over the fill, inside the border |
| Focus border | `var(--border-inform)` | Web |
| Skeleton fill | `var(--skeleton-on-white)` | |
| Skeleton wave | `var(--skeleton-wave)` | The shimmer's highlight |

The colour contract is two custom properties on the root — `--chips-action-fill` and
`--chips-action-border` — plus the root `color` that the slots, the Title and the Subtitle inherit. A
non-default colour for one part goes inline on that part (`style="color: var(--token)"`).

- Contrast on `Background/Primary`: Title ≈ 17.8:1 Day / ≈ 17.0:1 Night; Counter ≈ 5.25:1 / ≈ 7.92:1;
  the focus border ≈ 4.8:1 / ≈ 4.7:1 against the fill (above the 3:1 non-text floor).
- The Standard border (`Border/Default`, ≈ 1.3:1 / ≈ 2.2:1 against the fill) is decoration: the chip
  is identified by its text or icon, not by its edge.
- `TextAndIcon/Disabled` is below the contrast floor on purpose — a disabled control is exempt.
- The figures hold for the default fill. A re-pointed fill keeps the Title, the Counter and the
  Subtitle at 4.5:1 or more and the ring at 3:1; the Counter sets its own colour, so it is re-pointed
  together with the root colour.
- Forced colours (Windows High Contrast) drop `box-shadow`: the web draws a real outline in system
  colours instead — `ButtonBorder`, `Highlight` on focus, `GrayText` when disabled.
- **Figma flags:** the Specification frame writes the pressed overlay as "#000000, opacity 8%" — a
  detached copy in the press staging; the components use the effect style `State/PressedStateOverlay`
  (inset black 10%) = `--shadow-pressed`, the one press token (color-rules § 5). The Skeleton variants bind
  `Surface/OnWhite` — the same primitive as `Skeleton/OnWhite` in both themes; the web uses the
  Skeleton token and the shimmer, as every DS skeleton does. The Number Indicator in the private slot
  sets binds `Accent/Red 1`, while the Indicator itself is `Accent/Red 2` on both sizes.

---

## 7. Typography

| Element | Style | Tokens | Scaling |
|---|---|---|---|
| Title | Body/Main Body — 16/20, Suisse Intl Book | `var(--text-body-main-body-*)` | `full` (Figma binds `SP/150% ratio`) |
| Counter | Body/Main Body — 16/20, Suisse Intl Book | `var(--text-body-main-body-*)` | `full` |
| Subtitle | Caption/Caption — 12/16, Suisse Intl Book | `var(--text-caption-caption-*)` | `full` |

- The Title and the Subtitle are one line each; the chip hugs the longer of the two. Figma stages no
  overflow; the web caps the chip at its container's width and ends an over-long Title or Subtitle in
  an ellipsis — the accessible name stays whole.
- The Subtitle is Caption inside an interactive control — Figma's choice; the typography rules keep
  Caption for non-interactive text (§ 11), with one exception since 2026-11-12 (owner): the secondary line of a control, whose name the title carries — this Subtitle.
- The Counter is a number the product formats; the chip does not format it.

---

## 8. Spacing

Figma binds every container value to `SP/100% ratio` and the text and icon sizes to `SP/150% ratio`.
On the web every SP-bound value follows the SP mode (100 / 130 / 150%) — the repo's spacing tokens
carry no fixed-ratio set (a repo-wide deviation).

| Property | Token | @100% | Notes |
|---|---|---|---|
| Width | — | hugs | |
| Min width | `var(--sp-s64)` | 64 | An Icon chip is 64 wide |
| Min height — M | `var(--sp-s48)` | 48 | |
| Min height — S | `var(--sp-s40)` | 40 | |
| Padding — start / end | `var(--sp-s12)` | 12 | |
| Padding — top / bottom | `var(--sp-s0)` | 0 | The content is centred on the min height |
| Radius | `var(--sp-s96)` | full | Figma binds `s96` — a full pill at every size |
| Border | `var(--sp-s2)` | 2 | Drawn inside the box, outside the layout flow, as in Figma — it adds nothing to the size and never pushes the content in. The web draws it as an inset ring (`box-shadow`) |
| Gap — slot ↔ text | `var(--sp-s0)` | 0 | The text's own side padding makes the gap |
| Text padding — start / end | `var(--sp-s4)` | 4 | |
| Gap — Title ↔ Counter | `var(--sp-s4)` | 4 | |
| Gap — Title ↔ Subtitle | `var(--sp-s0)` | 0 | |
| Slot | `var(--sp-s24)` | 24 × 24 minimum | Hugs its content — a wider Number Indicator widens it; content centred |
| Indicator | `var(--sp-s12)` | 12 | Simple L; flush with the container's top end corner |
| Skeleton width — Icon | `var(--sp-s64)` | 64 | Fixed |
| Skeleton width — Icon + Title | `var(--sp-s124)` | 124 | Fixed — there is no title to hug |

At 100%: a title-only M chip is 12 + 4 + title + 4 + 12 wide, and 48 high; an Icon chip is 64 × 48
(M) or 64 × 40 (S).

---

## 9. Usage context

### When to use ChipsAction

- A value entered in a sheet or a modal and then shown inside the chip — "Schedule delivery" becomes
  "20 November, 09:00 AM" — with the Chevron in the end slot.
- Ready-made values that fill a text field — quick replies in a chat ("I'm here", "Where are you?"),
  a standard weight or size.
- A compact icon-only action in a row of chips.
- A value that can be cleared: the Delete icon in the end slot, the tap removes it.

### When not to use

- To pick one or several options from a set and keep them selected — that is
  [ChipsChoice](https://super-dollop-pzmo65r.pages.github.io/chips-choice.md).
- For the main action of a screen — a [Button](https://super-dollop-pzmo65r.pages.github.io/button.md).
- For a static label or status — a [Tag](https://super-dollop-pzmo65r.pages.github.io/tag.md); a Tag is not interactive.
- To switch between views of the same content — a [SegmentedControl](https://super-dollop-pzmo65r.pages.github.io/segmented-control.md).

### Related components

- [Indicator](https://super-dollop-pzmo65r.pages.github.io/indicator.md) — the Simple L dot on the corner and the Number Indicator L in a slot.
- [Button](https://super-dollop-pzmo65r.pages.github.io/button.md) — shares the `pushButton` press.
- [Tag](https://super-dollop-pzmo65r.pages.github.io/tag.md) — the non-interactive pill.
- [ChipsChoice](https://super-dollop-pzmo65r.pages.github.io/chips-choice.md) — the selectable pill on the same container; shares the start-slot set.
- [ChipsArea](https://super-dollop-pzmo65r.pages.github.io/chips-area.md) — the row and the group: the Suggest preset.

---

## 10. Accessibility

Brief summary. Full spec: [`chips-action-a11y.md`](https://super-dollop-pzmo65r.pages.github.io/chips-action.md).

- **One button**: the whole chip is one target, announced as a button — "[Title], [Counter],
  [Subtitle], Button". Slot icons are not announced.
- **Icon-only chip**: the screen gives it a label that names the action — never the icon's name.
- **Indicator**: its meaning comes from the screen — "new items" for a dot, "2 new items" for a count —
  appended after the text.
- **Chevron**: the hint says what opens — "Double-tap to choose [field]" (TalkBack), "Opens [field]
  selection." (VoiceOver); on the web `aria-haspopup="dialog"` and the field heading as the
  description. When the sheet closes, the focus returns to the chip.
- **Delete**: the name carries the verb — "Remove [Title]" on all three platforms; after the removal
  the focus moves to a neighbour (or the row's owner), then "[Title] removed" is announced.
- **Number Indicator in a slot**: read with the screen's word — "2 applied", never "2" alone.
- **Disabled**: TalkBack appends "Disabled", VoiceOver "Dimmed"; both keep it reachable, ignore the
  activation and drop the hint.
- **Skeleton**: not announced, not focusable — the loading container announces once.
- **Touch target**: M is 48 high, above the 44 floor of the typography rules (§ 12). S is 40 — below
  that floor, as Button S, and above WCAG 2.5.8's 24 × 24 — an accepted exception (owner, 2026-11-12; `typography-rules.md` § 12): WCAG 2.5.8 AA met at every mode, 52 at 130 %. Every chip is at least 64 wide.
- **Focus** (web): the ring turns `Border/Inform`; forced colours draw a system-colour outline.
- Text scaling: all three text styles scale to 150%; the min height is an SP token, so the chip grows
  with them on the web.

---

## 11. Analytics and coverage contract

Contract per [`prototype-analytics-and-coverage.md`](https://github.com/inDriver/oymyakon-ds/blob/main/docs/prototype-analytics-and-coverage.md).

| Field | Value |
|---|---|
| `data-ds-component` | `chips-action` |
| Coverage unit | yes — one root, one DS component instance |
| Tap target model | root — the whole chip is one `<button>` |
| Actions | `tap` |
| Internal targets | none |
| Emits value | no — the chip shows the host's value; the host owns it |

Attribute model: `data-ds-preset` = the size (`m`, `s`); `data-ds-variant` = the Chip Type
(`icon-title`, `icon`); `data-ds-state` = `standard`, `disabled` or `skeleton`. A disabled chip keeps
its attribution and emits no tap. RTL is the reading direction, not a state. The nested Indicator
carries no `data-ds-*` of its own.

```html
<!-- Action chip: opens a modal sheet, the Chevron in the end slot; the field heading describes it -->
<h3 id="pickup-time">Pickup time</h3>   <!-- the screen's own heading; not part of the component -->
<button type="button" class="chips-action" aria-haspopup="dialog" aria-describedby="pickup-time"
        data-ds-component="chips-action" data-ds-component-id="delivery.schedule"
        data-ds-preset="m" data-ds-variant="icon-title" data-ds-state="standard"
        data-ds-action="tap">
  <span class="chips-action__content">
    <span class="chips-action__text">
      <span class="chips-action__line">
        <span class="chips-action__title">Schedule delivery</span>
      </span>
    </span>
    <span class="chips-action__slot chips-action__slot--end" aria-hidden="true"><svg …>chevron-down</svg></span>
  </span>
</button>

<!-- Icon type, S, with the corner Indicator -->
<button type="button" class="chips-action chips-action--s chips-action--icon" aria-label="Favourites, new items"
        data-ds-component="chips-action" data-ds-component-id="menu.favourites"
        data-ds-preset="s" data-ds-variant="icon" data-ds-state="standard"
        data-ds-action="tap">
  <span class="chips-action__content">
    <span class="chips-action__slot chips-action__slot--start" aria-hidden="true"><svg …>heart-outline</svg></span>
  </span>
  <span class="indicator indicator--simple indicator--l chips-action__indicator" aria-hidden="true"></span>
</button>
```

A chip with a title takes its name from its own text — the Title, the Counter and the Subtitle, in
that order, with a `.visually-hidden` ", " before the Counter and before the Subtitle (so "Breakfast"
and "12" never run together into one word); an Indicator's meaning is a `.visually-hidden` span after them ("new items"). An Icon chip
takes an `aria-label`. A chip that opens a modal sheet carries `aria-haspopup="dialog"` (dropped while disabled) and the field heading as `aria-describedby`; a Delete chip is named by `aria-label="Remove [Title]"`; a Number Indicator in a slot adds a `.visually-hidden` phrase after the text (", 2 applied"). Disabled is the native `disabled` attribute plus `data-ds-state="disabled"`;
Skeleton is `.chips-action--skeleton` with `aria-hidden="true"`, `inert` and no content.

---

## Changelog

| Version | Date | Change |
|---|---|---|
| 3.1.5 | 2026-11-12 | `aria-disabled="true"` renders as Disabled — drawn and announced the same, refusing the activation, focusable — for a disabled ChipsArea (3.0.1). |
| 3.1.4 | 2026-11-12 | The Caption Subtitle inside the control is accepted — the typography rules' exception for a control's secondary line (owner ruling; `typography-rules.md` § 11.2). Status Draft → Ready (owner). |
| 3.1.3 | 2026-11-12 | S at 40 recorded as an accepted exception to the 44 touch-target floor, as Button S (owner ruling; `typography-rules.md` § 12). The Caption-subtitle flag stays open. |
| 3.1.2 | 2026-11-03 | ChipsArea shipped on the web: § 1 and § 9 link [ChipsArea](https://super-dollop-pzmo65r.pages.github.io/chips-area.md) (the Suggest preset) in place of "Figma only". |
| 3.1.1 | 2026-10-29 | The pressed-overlay flag corrected: the frame's "#000000, opacity 8%" is a detached copy; the components use the style `State/PressedStateOverlay` (10%) = `--shadow-pressed`, the one press token. ChipsChoice 3.0.0 shipped on the web: the description, "When not to use" and "Related components" link to it instead of calling it Figma only. Page: non-tokens moved out of token chips (`pushButton` → plain text, the curve → `var(--curve-standard-ease-in-out)`, the `--component-*` glob → code). No change to the component. |
| 3.1.0 | 2026-10-27 | Initial spec, from the Figma `[ChipsAction] 3.1` page in the main components file (page `6388:540`): the `M-ChipsAction` (`10997:5719`) and `S-ChipsAction` (`22962:21969`) sets, the private slot sets (`10086:29717`, `10086:29850`), the press staging (`10318:22084`), the 3.0 Chips Specification frame (`6390:17466`) and the `Update 3.1` frame (`22838:14180`). A pill-shaped button — min `s64` × `s48` (M) / `s40` (S), padding `s12` at the sides, radius full (`s96`), a `s2` inside `Border/Default` border kept outside the layout as in Figma (an inset ring on the web) on `Background/Primary` (3.1: was `Surface/OnGrey`). Chip Type Icon + Title (the Title in Main Body with an optional Counter in Secondary after it and an optional Caption Subtitle under it; start and end `s24` slots optional) and Icon (the start slot alone). Slots: an icon or a Number Indicator L; the end slot also the Chevron or the Delete icon; Avatar not on the web. Optional Simple L Indicator on the top end corner. States Standard (Figma Default) · Disabled (content in `TextAndIcon/Disabled`, fill and border unchanged, no Indicator) · Skeleton (an empty `s64` / `s124` pill on `Skeleton/OnWhite` with the shimmer); Hover / Pressed = the `--shadow-pressed` overlay, Pressed also scales the content to 95% (`pushButton`) while the pill and the Indicator stay still; Focus (web) = `Border/Inform`. RTL mirrors the row and the Indicator. Two presets (`m`, `s`); colour defaults re-pointable through `--chips-action-fill` / `--chips-action-border` and the root colour. Figma flags: the pressed overlay written as a raw "#000000, opacity 8%"; the Skeleton variants bind `Surface/OnWhite`; the slot sets' Number Indicator binds `Accent/Red 1` (the Indicator is Red 2). Spec-reviewer (0 critical, 1 high, 4 medium, 6 low) and a11y-reviewer (0 critical, 3 high, 7 medium, 5 low) passes folded in before release: a forced-colours outline (the ring is a `box-shadow`); a Delete chip named "Remove [Title]" on every platform (was the Title + a hint); a slot's Number Indicator spoken with the screen's word; the TalkBack Chevron hint names the field, the field heading is the chip's description on the web; a disabled chip drops its hint and `aria-haspopup`; focus after a removal (neighbour, else the row's owner) before the announcement; long text capped with an ellipsis; a contrast floor for re-pointed fills; reduced motion = the press applies at once (not "no scale"); the focus ring eases with the overlay; `onlyWhen` gating in the contract. Flagged for the owner: S at 40 is under the 44 touch-target floor of the typography rules (as Button S); Caption in an interactive control (the Figma Subtitle). |

---

# ChipsAction — Accessibility

ChipsAction is **one button**: the whole chip is the tap target and one focus stop, whatever it holds.
Its name is its text, read in visual order — **[Title], [Counter], [Subtitle]** — and the icons in its
slots are not announced (Specification frame, "Accessibility. Android. TalkBack" /
"Accessibility. iOS. VoiceOver", the Action blocks).

The screen supplies three things the chip cannot know:

- **An Icon chip's label** — the action it runs ("Favourites", "Call the driver"), never the icon's
  name ("heart").
- **The Indicator's meaning** — what the dot or the count stands for: "new items" for a Simple dot,
  "2 new items" for a Number Indicator. It is appended after the text.
- **What the tap does** when the end slot shows it: the Chevron — the chip opens a choice, and the
  hint names the field; the Delete icon — the tap removes the value, and the **name** carries the verb
  ("Remove Courier"), since hints can be switched off and a one-tap removal must not sound like any
  other chip.

| Visible | Announced (TalkBack) |
|---|---|
| Breakfast 12 / Schedule delivery | "Breakfast, 12, Schedule delivery, Button, Double-tap to activate" |
| Breakfast 12 / Schedule delivery + dot | "Breakfast, 12, Schedule delivery, new items, Button, Double-tap to activate" |
| Breakfast 12 / Schedule delivery + count 2 | "Breakfast, 12, Schedule delivery, 2 new items, Button, Double-tap to activate" |
| Schedule delivery ⌄ | "Schedule delivery, Button, Double-tap to choose pickup time" |
| 20 November, 09:00 AM ⌄ (after the sheet) | "20 November, 09:00 AM, Button, Double-tap to choose pickup time" |
| Courier ✕ | "Remove Courier, Button, Double-tap to activate" |
| Filters 2 (a count in the end slot) | "Filters, 2 applied, Button, Double-tap to activate" |

The first three rows are the Figma voiced previews. The last two are an Action chip from the Figma
usage example: once the value is entered in the sheet, it replaces the title — the chip reads the
value as its name. The field's own heading ("Pickup time") is the screen's: the hint names it, and on
the web it is the chip's description, so a person who lands on the chip after the sheet still hears what
the value is.

---

## Android · TalkBack

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| Chip (Icon + Title) | "[Title], [Counter], [Subtitle]" — `contentDescription`; "Remove [Title]" with Delete | — | Button — `Role.Button` | "Double-tap to activate." — `onClick(label = "activate")`; "choose [field]" with the Chevron |
| Chip (Icon) | The screen's action name — `contentDescription` | — | Button — `Role.Button` | As above |
| Indicator, or a Number Indicator in a slot | Its meaning from the screen, appended to the label | — | — | — |
| Slot icons, Chevron, Delete icon | — | — | Decorative — not nodes | — |

Voiced previews:

- "Breakfast, 12, Schedule delivery, Button, Double-tap to activate."
- "Favourites, new items, Button, Double-tap to activate."
- "20 November, 09:00 AM, Button, Double-tap to choose pickup time."
- "Remove Courier, Button, Double-tap to activate."

### Edge states

- **Disabled:** `enabled = false` (`disabled()` semantics). TalkBack keeps the chip in swipe
  navigation, appends "Disabled" and drops the hint: "Breakfast, Button, Disabled." A double-tap does
  nothing. The Disabled chip carries no Indicator, so nothing is appended for it.
- **After the input sheet closes** (an Action chip): focus returns to the chip, which now reads the
  value as its title — "20 November, 09:00 AM". No separate announcement.
- **Delete:** after the removal the chip leaves the row. The focus moves **first** — to the next chip
  in the row, to the previous one when it was the last, or to the row's owner (the field heading or
  the control that holds the row) when no chip is left — and **then** the removal is announced once,
  politely: "[Title] removed".
- **Number Indicator in a slot:** read as part of the label, with the screen's word — "2 new items",
  never "2" alone.
- **Skeleton:** not announced, not focusable — `clearAndSetSemantics {}` on the shape; the loading
  container announces once, politely.
- **RTL:** the row mirrors; the label order stays Title, Counter, Subtitle — the reading order of the
  language.
- **Text scaling:** Title, Counter and Subtitle scale to 150%, the DS maximum.

---

## iOS · VoiceOver

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| Chip (Icon + Title) | "[Title], [Counter], [Subtitle]" — `accessibilityLabel`; "Remove [Title]" with Delete | — | `.button` | — by default; "Opens [field] selection." with the Chevron — `accessibilityHint` |
| Chip (Icon) | The screen's action name — `accessibilityLabel` | — | `.button` | As above |
| Indicator, or a Number Indicator in a slot | Its meaning, appended to the label | — | — | — |
| Slot icons, Chevron, Delete icon | — | — | Decorative — `accessibilityHidden(true)` | — |

Voiced previews:

- "Breakfast, 12, Schedule delivery, Button."
- "Breakfast, 12, Schedule delivery, 2 new items, Button."
- "20 November, 09:00 AM, Button. Opens pickup time selection."
- "Remove Courier, Button."

Apple's hint idiom — a verb phrase that describes the result, never the gesture. The Figma iOS
previews add "Double-tap to activate" to the Indicator rows; VoiceOver speaks its own usage hint after
a pause, so the chip sets none of its own for a plain action.

### Edge states

- **Disabled:** `.notEnabled` — VoiceOver appends "Dimmed": "Breakfast, Dimmed, Button." It stays in
  navigation; a double-tap does nothing. The hint is cleared while disabled — VoiceOver would still
  speak it, and a dimmed Chevron chip must not say it opens anything.
- **After the input sheet closes:** focus returns to the chip (`UIAccessibility.post(notification:
  .layoutChanged, argument: chip)`), which reads the new value.
- **Delete:** as on Android — the focus moves first (`.layoutChanged` with the neighbour or the row's
  owner as the argument), then the announcement (`AccessibilityNotification.Announcement`) "[Title]
  removed" is posted; posted together, the announcement is easily cut off by the focus change.
- **Skeleton:** `accessibilityHidden(true)` on the shape (`.isLoading(true)` alone does not hide it);
  the loading container announces once.
- **RTL / Dynamic Type:** as on Android.

---

## Web preview (reference)

- **A `<button type="button">`.** A chip with a title takes its accessible name from its own text —
  Title, Counter and Subtitle, in DOM order, with a `.visually-hidden` ", " before the Counter and
  before the Subtitle. Without it the Title and the Counter sit side by side with no text between
  them, and the name can run together into one word ("Breakfast12"). The separator is absolutely
  positioned, so it changes nothing in the layout. The slots are `aria-hidden="true"`. An Indicator's
  meaning is a `.visually-hidden` span after the text ("new items"); the Indicator element itself is
  `aria-hidden="true"`.
- **Number Indicator in a slot:** the slot is `aria-hidden`, so its meaning is a `.visually-hidden`
  phrase after the text (", 2 applied"); on an Icon chip it joins the `aria-label`.
- **Icon chip:** `aria-label` with the action name (plus the Indicator's meaning, when it shows one).
- **Chevron:** `aria-haspopup="dialog"` when the chip opens a **modal** sheet or dialog — it takes the
  focus, so `aria-expanded` is not used; a non-modal sheet takes `aria-expanded`. On close the dialog
  returns the focus to the chip. The field heading is the chip's description (`aria-describedby`).
- **Delete:** `aria-label="Remove [Title]"` — the visible Title stays inside the name (label in name,
  2.5.3). Before the chip is removed the page moves the focus with `.focus()` to the neighbour or the
  row's owner, so it never falls to `<body>`; then a polite live region says "[Title] removed".
- **Disabled:** the native `disabled` attribute — the chip leaves the Tab order and stays readable in
  browse mode; `aria-haspopup` is dropped while disabled. Inside a disabled ChipsArea the chip carries
  `aria-disabled="true"` instead — focusable, drawn and announced the same, refusing the activation
  (ChipsArea 3.0.1).
- **Long text:** the chip is capped at its container's width and an over-long Title or Subtitle ends
  in an ellipsis on the screen; the accessible name stays whole.
- **Skeleton:** `aria-hidden="true"`, `inert`, no content; the loading region around the row
  announces.
- **Keyboard:** Tab reaches the chip; Enter and Space activate. In a row of chips each chip is its own
  Tab stop — the row is not a composite widget.
- **Focus:** `:focus-visible` turns the `s2` ring `var(--border-inform)` — ≈ 4.8:1 against the
  fill in Day, ≈ 4.7:1 in Night. The ring is the chip's own border, so a row of chips never clips it.
  The change from the default ring is ≈ 3.8:1 Day / ≈ 2.1:1 Night — informational (2.4.13 is AAA).
- **Forced colours:** Windows High Contrast drops `box-shadow`, so the ring and the overlay vanish; a
  real outline in system colours stands in — `ButtonBorder`, `Highlight` on focus, `GrayText` when
  disabled.
- **Re-pointed colours:** the contrast figures hold for the default fill. A re-pointed fill keeps the
  Title, the Counter and the Subtitle at 4.5:1 or more and the ring at 3:1; the Counter sets its own
  colour, so it is re-pointed with the root colour.
- **Target size:** M is `s48` high, above the `s44` floor of the typography rules (§ 12, iOS 44 pt).
  S is `s40` — below that floor and Material's 48 dp, above WCAG 2.5.8's 24 × 24, as Button S. Recorded as
  an accepted exception (owner, 2026-11-12; `typography-rules.md` § 12): WCAG 2.5.8 AA met at every mode, 52 at 130 %; the drawn size is the target.
  Every chip is at least `s64` wide. The SP modes lift S to 52 at 130% and 60 at 150%.
- **Caption in a control:** the Subtitle is Caption (12 / 16) — Figma's choice; the typography rules
  keep Caption for non-interactive text (§ 11), except the secondary line of a control whose name
  the title carries — this Subtitle (owner, 2026-11-12). The accessible name comes from the title.

---

## Checklist

- [ ] The whole chip is one focus stop and one target
- [ ] An Icon chip has a label naming the action, not the icon
- [ ] Slot icons, the Chevron and the Delete icon are hidden from assistive tech
- [ ] The Indicator's meaning — and a slot's count — is in the name, after the text
- [ ] A Delete chip is named "Remove [Title]"; after the removal the focus moves before the announcement
- [ ] Disabled: "Disabled" (TalkBack) / "Dimmed" (VoiceOver), reachable, no action, no hint
- [ ] Skeleton is hidden and not focusable
- [ ] After a sheet closes, focus is back on the chip

---

## Machine contract — `specs/components/chips-action/capabilities.json`

Axes, allowed values, defaults, constraints and CSS/Figma bindings. Read this instead of guessing what the component can do.

```json
{
  "$schema": "../component-capabilities.schema.json",
  "id": "chips-action",
  "name": "ChipsAction",
  "version": "3.1.5",
  "description": "A pill-shaped button that runs one action: it opens an input (a sheet or a modal) and then shows the entered value as its title, or fills a field with a ready-made value. Not selectable. Sizes M (min s48) and S (min s40); Chip Type Icon + Title or Icon; optional start / end s24 slots, Counter, Subtitle and a corner Indicator. States Standard · Disabled · Skeleton.",
  "files": {
    "spec": "specs/components/chips-action/chips-action.md",
    "a11y": "specs/components/chips-action/chips-action-a11y.md",
    "preview": "src/chips-action.njk",
    "css": "src/shared/shared.css"
  },
  "figma": {
    "library": "🕹️ Oymyakon (components) — main file",
    "fileKey": "7vdl5YkZFDWvh9QvSmydsH",
    "componentSets": {
      "M-ChipsAction": {
        "key": "b99e0481b18bc6aea6fe9d9184fcb99d6a190e3b",
        "note": "Set 10997:5719 on page [ChipsAction] 3.1 (6388:540) — RTL (false, true) × Chip Type (Icon, Icon+Title) × State (Default, Disabled, Skeleton); booleans 🔴Slot#1, 🔵Slot#2, Title, Counter, Subtitle, Indicator; texts Title / Counter / Subtitle."
      },
      "S-ChipsAction": {
        "key": "22777fb2f496d38e0e712d774dd8ce8bb104e20a",
        "note": "Set 22962:21969, same page — the same axes and properties; min height s40."
      }
    },
    "capturedAt": "2026-10-27"
  },
  "root": {
    "class": "chips-action",
    "dataDsComponent": "chips-action"
  },
  "anatomy": {
    "content": {
      "class": "chips-action__content",
      "notes": "The row of the slots and the text, gap s0. The part that scales to 95% on press (pushButton) — the Figma press staging (.ChipsItemPressedAnimation 10318:22084) scales this inner frame as one; the pill and the Indicator stay still."
    },
    "startSlot": {
      "class": "chips-action__slot--start",
      "optional": true,
      "notes": "Figma 🔴Slot#1 (private set 10086:29717): hugs, min s24, content centred — an icon (any DS icon, s24) or a Number Indicator L. Figma also offers an Avatar — no web build. On in Chip Type Icon (the only part), off by default in Icon + Title. aria-hidden; a Number Indicator's meaning is spoken as a .visually-hidden phrase (or joins an Icon chip's aria-label)."
    },
    "text": {
      "class": "chips-action__text",
      "onlyWhen": {
        "chipType": [
          "icon-title"
        ]
      },
      "optional": true,
      "notes": "Figma TextContainer: a centred column, s4 padding at the start and end (the gap to a slot or the edge). Absent in Chip Type Icon."
    },
    "title": {
      "class": "chips-action__title",
      "onlyWhen": {
        "chipType": [
          "icon-title"
        ]
      },
      "notes": "One line, Body/Main Body, the root colour (TextAndIcon/Primary). The chip hugs it; capped at the container's width, it ends in an ellipsis (the accessible name stays whole). An Action chip shows the entered value here once the sheet closes. A .visually-hidden \", \" separates it from the Counter and the Subtitle in the accessible name."
    },
    "counter": {
      "class": "chips-action__counter",
      "onlyWhen": {
        "chipType": [
          "icon-title"
        ]
      },
      "optional": true,
      "notes": "Off by default. A number after the title, s4 from it (in .chips-action__line), Body/Main Body, TextAndIcon/Secondary."
    },
    "subtitle": {
      "class": "chips-action__subtitle",
      "onlyWhen": {
        "chipType": [
          "icon-title"
        ]
      },
      "optional": true,
      "notes": "Off by default. One line under the title line, Caption/Caption, the root colour."
    },
    "endSlot": {
      "class": "chips-action__slot--end",
      "onlyWhen": {
        "chipType": [
          "icon-title"
        ]
      },
      "optional": true,
      "notes": "Figma 🔵Slot#2 (private set 10086:29850): an icon, a Number Indicator L, the Chevron (chevron-down — the chip opens a choice: aria-haspopup=\"dialog\", the field heading as aria-describedby, the TalkBack hint names the field) or the Delete icon (close-small — the tap removes the value: the chip is named \"Remove [Title]\" on every platform). A Number Indicator's meaning is a .visually-hidden phrase after the text (\", 2 applied\"). Figma also offers an Avatar — no web build. aria-hidden."
    },
    "indicator": {
      "class": "chips-action__indicator",
      "onlyWhen": {
        "state": [
          "standard"
        ]
      },
      "optional": true,
      "notes": "An Indicator Simple L (.indicator.indicator--simple.indicator--l), absolute on the pill's top end corner, flush (s0) against the outer edge — the border is an inset ring that takes no space. Outside __content — it never scales. aria-hidden; its meaning is a .visually-hidden phrase from the screen after the text. Standard only: the Figma Disabled and Skeleton variants carry no Indicator layer."
    }
  },
  "axes": {
    "size": {
      "title": "Size",
      "type": "enum",
      "values": [
        "m",
        "s"
      ],
      "default": "m",
      "css": {
        "modifier": ".chips-action--s",
        "mechanism": "m is the bare .chips-action (min height s48); .chips-action--s sets min height s40. Nothing else differs."
      },
      "figma": {
        "kind": "component-set",
        "values": {
          "m": "M-ChipsAction",
          "s": "S-ChipsAction"
        }
      },
      "notes": "The web presets — data-ds-preset=\"m\" / \"s\"."
    },
    "chipType": {
      "title": "Chip Type",
      "type": "enum",
      "values": [
        "icon-title",
        "icon"
      ],
      "default": "icon-title",
      "css": {
        "modifier": ".chips-action--icon",
        "mechanism": "icon = .chips-action--icon with the start slot alone (no .chips-action__text) and an aria-label; the modifier also sets the Skeleton width to s64. icon-title = the title with the slots optional."
      },
      "figma": {
        "kind": "variant-property",
        "property": "Chip Type",
        "values": {
          "icon-title": "Icon+Title",
          "icon": "Icon"
        }
      }
    },
    "state": {
      "title": "State",
      "type": "enum",
      "values": [
        "standard",
        "disabled",
        "skeleton"
      ],
      "default": "standard",
      "css": {
        "mechanism": "standard is the bare chip; disabled = the native disabled attribute (:disabled — the content turns TextAndIcon/Disabled, fill and border unchanged); .chips-action--skeleton = an empty borderless pill on Skeleton/OnWhite with --pattern-shimmer, s124 wide (s64 with --icon)"
      },
      "figma": {
        "kind": "variant-property",
        "property": "State",
        "values": {
          "standard": "Default",
          "disabled": "Disabled",
          "skeleton": "Skeleton"
        }
      }
    },
    "startSlot": {
      "title": "Start slot",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "the .chips-action__slot--start element present or absent"
      },
      "figma": {
        "kind": "variant-property",
        "property": "🔴Slot#1",
        "notes": "A BOOLEAN component property (🔴Slot#1#9985:24), false by default; the Icon variants show the slot without it."
      }
    },
    "counter": {
      "title": "Counter",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "the .chips-action__counter element present or absent"
      },
      "figma": {
        "kind": "variant-property",
        "property": "Counter",
        "notes": "A BOOLEAN (Counter#9987:52) plus the TEXT property Counter Text."
      },
      "notes": "Icon + Title only (anatomy onlyWhen chipType=icon-title)."
    },
    "subtitle": {
      "title": "Subtitle",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "the .chips-action__subtitle element present or absent"
      },
      "figma": {
        "kind": "variant-property",
        "property": "Subtitle",
        "notes": "A BOOLEAN (Subtitle#9987:45) plus the TEXT property Subtitle Text."
      },
      "notes": "Icon + Title only (anatomy onlyWhen chipType=icon-title)."
    },
    "endSlot": {
      "title": "End slot",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "the .chips-action__slot--end element present or absent"
      },
      "figma": {
        "kind": "variant-property",
        "property": "🔵Slot#2",
        "notes": "A BOOLEAN component property (🔵Slot#2#9987:31), false by default."
      },
      "notes": "Icon + Title only (anatomy onlyWhen chipType=icon-title)."
    },
    "indicator": {
      "title": "Indicator",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "the .indicator.indicator--simple.indicator--l.chips-action__indicator element present or absent"
      },
      "figma": {
        "kind": "variant-property",
        "property": "Indicator",
        "notes": "A BOOLEAN (Indicator#9987:59); the Disabled and Skeleton variants carry no Indicator layer."
      }
    },
    "rtl": {
      "title": "RTL",
      "type": "boolean",
      "default": false,
      "css": {
        "mechanism": "dir=\"rtl\" on the root or an ancestor: the row mirrors (start slot right, end slot left, Counter left of the Title), the Indicator moves to the top left corner (inset-inline-end), the skeleton sweep reverses"
      },
      "figma": {
        "kind": "variant-property",
        "property": "RTL"
      }
    },
    "fill": {
      "title": "Fill",
      "type": "token",
      "tokens": [
        "--background-primary"
      ],
      "default": "--background-primary",
      "customizable": "any DS colour token (Specification frame: \"You may use any color from the DS\")",
      "css": {
        "customProperty": "--chips-action-fill"
      },
      "figma": {
        "kind": "none",
        "notes": "An instance override of the container fill; 3.1 changed the default from Surface/OnGrey to Background/Primary."
      }
    },
    "borderColor": {
      "title": "Border colour",
      "type": "token",
      "tokens": [
        "--border-default"
      ],
      "default": "--border-default",
      "customizable": "any DS colour token",
      "css": {
        "customProperty": "--chips-action-border"
      },
      "figma": {
        "kind": "none",
        "notes": "An instance override of the s2 inside stroke — drawn as an inset ring (box-shadow) that takes no space, as Figma excludes the stroke from the layout. Focus re-points the internal --chips-action-ring to --border-inform, over any re-pointed border."
      }
    }
  },
  "states": {
    "default": [
      "standard",
      "disabled",
      "skeleton"
    ],
    "interaction": [
      "standard",
      "hover",
      "pressed",
      "focused"
    ]
  },
  "constraints": [
    "One button, one target, one action — the slots are never separate buttons; the Delete icon is a cue for the chip's own action.",
    "Not selectable: no Active / selected state and no aria-pressed / aria-checked — selection is ChipsChoice (specs/components/chips-choice/).",
    "Hugs its content: min width s64, min height s48 (M) / s40 (S), padding s12 at the start and end and s0 top / bottom, radius s96 (full), a s2 inside border that takes no space (an inset ring — a \"Title\" chip is 12 + 4 + 32 + 4 + 12 = 64, as in Figma). Never a fixed size — the Skeleton is the one exception (s124, or s64 with --icon).",
    "A chip always shows an icon or a title; an Icon chip carries an aria-label naming the action, never the icon.",
    "Chip Type icon = the start slot alone: no text, no Counter, no Subtitle, no end slot (anatomy onlyWhen).",
    "Title and Subtitle are one line each (white-space: nowrap); the chip is capped at its container's width (max-width: 100%) and an over-long Title or Subtitle ends in an ellipsis.",
    "Press = pushButton: the content (__content) scales to 95% and the --shadow-pressed overlay comes in, via --component-push-button-press / -release; the pill and the Indicator never move. Hover (pointer) = the overlay alone.",
    "Disabled is a token swap on the content (TextAndIcon/Disabled) — never opacity; fill and border unchanged; no Indicator; no hover, no press.",
    "Focus (web) turns the ring Border/Inform (the internal --chips-action-ring) — no outline ring.",
    "No motion tokens declared on the component and no reduced-motion override — both live at the token (motion.css).",
    "Forced colours (Windows High Contrast) drop box-shadow: an outline in system colours stands in (ButtonBorder; Highlight on focus; GrayText when disabled).",
    "A Delete chip is named \"Remove [Title]\" (web aria-label); a disabled chip drops aria-haspopup and its hint."
  ],
  "analytics": {
    "dataDsComponent": "chips-action",
    "action": "tap",
    "notes": "Coverage unit, the root is the one target. data-ds-preset = the size (m / s); data-ds-variant = the Chip Type (icon-title / icon); data-ds-state = standard / disabled / skeleton. No value emitted — the host owns the value the chip shows. A disabled chip keeps its attribution and emits no tap; the nested Indicator carries no data-ds-*."
  },
  "rtl": {
    "supported": true,
    "notes": "The row mirrors and the corner Indicator moves to the top left; the label order stays Title, Counter, Subtitle (the language's reading order). chevron-down, close-small and the heart are symmetric — no glyph flips."
  }
}
```
