@expressivecss/mcp-server 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/CHANGELOG.md +16 -0
- package/README.md +7 -4
- package/capability-roadmap.json +1 -1
- package/component-decisions.json +1 -1
- package/component-guides.json +42 -42
- package/contract.json +4 -3
- package/package.json +1 -1
- package/semantics-data.json +1 -1
- package/server.js +22 -11
- package/smoke.mjs +12 -0
package/component-guides.json
CHANGED
|
@@ -1,171 +1,171 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedBy": "mcp/expressivecss/scripts/sync-guides.mjs",
|
|
4
|
-
"frameworkVersion": "0.
|
|
4
|
+
"frameworkVersion": "0.12.0",
|
|
5
5
|
"guides": [
|
|
6
6
|
{
|
|
7
7
|
"file": "app-bar.md",
|
|
8
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### App bar\nMaterial Design 3 top app bars, from the HTML.\n\nComponent ID: `app-bar`\n\n[Component documentation](https://www.expressivecss.com/navbar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navbar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
8
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### App bar\nMaterial Design 3 top app bars, from the HTML.\n\nComponent ID: `app-bar`\n\n[Component documentation](https://www.expressivecss.com/navbar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navbar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/app-bars/overview)\n\nExample: A Home/Search/Profile row belongs in navigation, even if placed at the top. Keep the app bar for the title and screen actions.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Google replaces baseline medium/large bars with flexible variants. ExpressiveCSS medium and large already mean medium-flexible and large-flexible; keep those classes.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/app-bars/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/app-bars/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/app-bars/guidelines).\n\nSupport (2026-09-17, `llm.md#navbar`): Small, medium flexible, large flexible, and search app bars.\n\nWeb adaptation: Native header/nav composition; AppBar owns scroll collapse and search expansion.\n\nKnown boundary: Native zoom, screen-reader announcements, contrast themes and physical mobile keyboard behavior remain pending manual review.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#app-bar).\n\n#### Contract\n\nMaterial Design 3 top app bars, from the HTML.\n\nThe bar is the markup. A `<header>` whose child is a `<nav>` is a top app bar. Top app bars stay pinned to the top by default, without a helper class. The heading is the headline; wrap it in `<hgroup>` with a `<p>` for a subtitle. Icon-only links and buttons are the leading and trailing actions. A `<menu>` (or `<ul>`) holds text destinations. A `<search class=\"search-bar\">` in the nav is the search app bar. There is no `navbar`, `nav-wrapper`, or `brand-logo` class.\n\nSmall is 64dp at `title-large`. `medium` is the Expressive medium-flexible bar: 112dp / `headline-medium`, 136dp with a subtitle. `large` is large-flexible: 120dp / `display-small`, 152dp with a subtitle. `AppBar` (started by `AutoInit()`) collapses those two on scroll and opens the related search view when the search field is selected. Icons are 24dp in a 48dp target and inherit the header color so a fill + `on-*` pair stays readable.\n\n#### Syntax\n\n```html\n<header>\n <nav aria-label=\"Main\">\n <button type=\"button\" aria-label=\"Menu\">\n <span class=\"material-symbols\" aria-hidden=\"true\">menu</span>\n </button>\n <h2>Title</h2>\n <button type=\"button\" aria-label=\"Search\"><span class=\"material-symbols\" aria-hidden=\"true\">search</span></button>\n <button type=\"button\" aria-label=\"More\"><span class=\"material-symbols\" aria-hidden=\"true\">more_vert</span></button>\n </nav>\n</header>\n```\n\n#### Also documented\n\nThe Navbar section of the [API reference](https://www.expressivecss.com/llm.md) also covers Small, Destinations, Center-aligned, Medium and large flexible, Subtitle, Collapse, Fixed, Color, Menu, Search, Responsive navigation.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\nNo component-specific `semantics.json` rules apply to this guide.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"file": "autocomplete.md",
|
|
12
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Autocomplete\nSuggest values under a text field as the user types.\n\nComponent ID: `autocomplete`\n\n[Component documentation](https://www.expressivecss.com/autocomplete.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/autocomplete.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
12
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Autocomplete\nSuggest values under a text field as the user types.\n\nComponent ID: `autocomplete`\n\n[Component documentation](https://www.expressivecss.com/autocomplete.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/autocomplete.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Related Google guidance](https://m3.material.io/components/menus/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: related. Related guidance is not a dedicated component specification.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/menus/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/menus/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/menus/guidelines).\n\nSupport (2026-09-13, `llm.md#autocomplete`): Single and multi-select suggestions.\n\nWeb adaptation: Runtime combobox behavior attached to a text field; no standalone upstream component claim.\n\nKnown boundary: Generated status-info does not announce new suggestion counts or asynchronous results.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#autocomplete).\n\n#### Contract\n\nAutocomplete preserves the original suggestion dataset and selected display label while editing. Escape and Tab close from the input, cancel pending opening, and keep listbox options outside sequential Tab order.\n\n`isOpen` follows the suggestion menu through rerenders and dismissal. Selection changes emit a bubbling, composed `change` event from the input, so delegated form listeners can observe them.\n\nSuggest values under a text field as the user types.\n\n#### Syntax\n\n```html\n<div class=\"field\">\n <span class=\"material-symbols prefix\" aria-hidden=\"true\">textsms</span>\n <input type=\"text\" id=\"autocomplete-input\" class=\"autocomplete\" placeholder=\" \">\n <label for=\"autocomplete-input\">Autocomplete</label>\n</div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `data` | Array | `[]` | Suggestion list. Each item needs an `id`; `text`, `image`, and `description` are optional. |\n| `isMultiSelect` | Boolean | `false` | If true, several values can be selected. `onAutocomplete` receives an array. |\n| `maxMenuHeight` | String | `'300px'` | Max height of the suggestion menu. |\n| `i18n` | Object | See below | Partial overrides for live status messages. |\n| `onAutocomplete` | Function | `null` | Called after a selection (and when a default value is applied). Receives the selected entries. |\n| `onSearch` | Function | filters `id` and `text` | Called when input events change the search text, including paste, replacement and deletion without key events. Load or filter data, then call `setMenuItems`. |\n| `minLength` | Number | `1` | Characters required before suggestions open. `0` shows the list on click or focus. |\n| `menuOptions` | Object | see note | Options for Menu. Defaults include `autoFocus: false`, `closeOnClick: false`, and `coverTrigger: false`. |\n| `allowUnsafeHTML` | Boolean | `false` | If true, matched text is inserted as HTML. Only use sanitized data. |\n| `selected` | Array | `[]` | Initial selected ids, strings or numbers. An id without loaded data displays the id. Pass the selected ids to `setMenuItems` with the loaded data to resolve their labels. |\n\n#### Methods\n\n- `.open()`: Open the suggestion menu if the input meets `minLength`.\n- `.close()`: Close the suggestion menu.\n- `.selectOption()`: Select (or toggle, when multi-select) the entry with this id.\n- `.setMenuItems()`: Replace the visible suggestions. Optionally pass selected ids and whether to open the menu (default `true`).\n- `.destroy()`: Destroy the plugin instance, remove the menu, and tear down its event handlers.\n\n#### Also documented\n\nThe Autocomplete section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `autocomplete-options-are-options`: The suggestion list is a listbox; every entry in it is an option.\n- `field-container-class`: The field container is `.field`. `.input-field` matches nothing in the sheet - the only `.input-field` rule is `.chips.input-field`.\n- `field-icon-not-i`: <i> means idiomatic text, not icon. Use <span class=\"material-symbols\">.\n- `field-icon-hidden`: The ligature is read aloud. A field icon is decoration; the label names the control.\n- `field-icon-side`: A field icon must name its side with .prefix or .suffix. The positional fallback counts elements of the same *type*, which only ever worked for <i>.\n- `field-label-for`: A label that does not wrap its control has to name it. The floating label sits *after* the control and cannot wrap it, so it always needs `for`; a label that does wrap its control (the file input trigger) does not.\n- `field-control-id`: Without an id the label has nothing to point at.\n- `field-supporting-text-id`: Supporting and error text has to be referenceable to be announced with the control.\n- `field-supporting-text-linked`: A field with supporting text must point at it with aria-describedby, or the text is never read out with the control.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"file": "badges.md",
|
|
16
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Badges\nNotifications, counts, or status on navigation items and icons.\n\nComponent ID: `badges`\n\n[Component documentation](https://www.expressivecss.com/badges.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/badges.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
16
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Badges\nNotifications, counts, or status on navigation items and icons.\n\nComponent ID: `badges`\n\n[Component documentation](https://www.expressivecss.com/badges.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/badges.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/badges/overview)\n\nExample: An unread count belongs on the inbox icon as a badge. A selectable Unread filter needs a chip or selection control with its own name and state.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/badges/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/badges/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/badges/guidelines).\n\nSupport (2026-09-13, `llm.md#badges`): Small dot and large count badges.\n\nWeb adaptation: Expose counts through the enclosing control name when its icon is hidden.\n\nKnown boundary: A named count fixture is checked; changing counts, clipping and spoken updates remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#badges).\n\n#### Contract\n\nNotifications, counts, or status on navigation items and icons.\n\nA `<span class=\"badge\">` is the badge. Empty is the **small** 6dp dot; text is the **large** 16dp stadium. Nest it in the icon so it sits on the upper trailing edge of the 24dp glyph. Limit the label to four characters, including `+`. The default mapping is `error` / `on-error`.\n\nNesting has a consequence worth stating: **a badge inside a hidden icon is hidden with it.** `aria-hidden=\"true\"` covers the whole subtree, and `aria-hidden=\"false\"` on a descendant does not undo that — so a count that only exists inside a decorative icon is a count nobody hears. Two ways out, depending on what surrounds it:\n\n#### Syntax\n\n```html\n<span class=\"material-symbols\" role=\"img\" aria-label=\"Mail, unread\">mail<span class=\"badge\"></span></span>\n<span class=\"material-symbols\" role=\"img\" aria-label=\"Mail, 1 unread\">mail<span class=\"badge\">1</span></span>\n<span class=\"material-symbols\" role=\"img\" aria-label=\"Mail, 999+ unread\">mail<span class=\"badge\">999+</span></span>\n```\n\n#### Also documented\n\nThe Badges section of the [API reference](https://www.expressivecss.com/llm.md) also covers Small, Large, On navigation, In a list, Color.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `badge-count-survives-a-hidden-icon`: A badge inside a hidden icon is hidden with it - aria-hidden=\"false\" on a descendant does not undo that. Put the count in the control name (aria-label=\"Inbox, 3 unread\"), or move the badge out of the icon into the flow.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"file": "bottom-sheet.md",
|
|
20
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Bottom sheet\nSecondary content anchored to the bottom of the screen.\n\nComponent ID: `bottom-sheet`\n\n[Component documentation](https://www.expressivecss.com/bottom-sheet.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/bottom-sheet.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
20
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Bottom sheet\nSecondary content anchored to the bottom of the screen.\n\nComponent ID: `bottom-sheet`\n\n[Component documentation](https://www.expressivecss.com/bottom-sheet.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/bottom-sheet.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `shared-runtime`. [Google guidance](https://m3.material.io/components/bottom-sheets/overview)\n\n- expanded window: replace-with [side-sheet](./side-sheet.md). Persistent secondary content fits beside the main task.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/bottom-sheets/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/bottom-sheets/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/bottom-sheets/guidelines).\n\nSupport (2026-09-18, `llm.md#bottom-sheet`): Standard and modal bottom sheets.\n\nWeb adaptation: Native dialog.show()/showModal(); shared runtime handles dragging and dismissal.\n\nKnown boundary: The shared handle dismisses rather than cycling sheet heights. Long-content scrolling and enlarged-text action access are checked; native zoom and physical touch remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#bottom-sheet).\n\n#### Contract\n\nA recent flick dismisses the sheet even if the pointer stops moving at release. For short drags, pausing for at least 100ms or reversing direction lets it snap back.\n\nA `dialog.bottom-sheet` (or `.bottom`) is secondary content anchored to the bottom. Use it on Compact and Medium windows. `showModal()` is the modal variant (scrim). `show()` is the standard variant (no scrim). Same sheet either way: `surface-container-low`, 28dp top corners, 640dp max, 56dp side inset from the Medium breakpoint, 72dp top inset, 32×4 drag handle in a 48dp hit target. Drag the handle down to dismiss. A named `<button>` handle also dismisses on click, tap, <kbd>Enter</kbd>, or <kbd>Space</kbd>. A decorative handle needs another non-drag pointer and keyboard dismiss path, such as a `form method=\"dialog\"` close button. Verify native Escape against the opening mode, browser, and `closedby` policy.\n\n#### Syntax\n\n```html\n<dialog class=\"bottom-sheet\" aria-labelledby=\"open-file-title\">\n <h2 id=\"open-file-title\">Open file</h2>\n <div>…</div>\n <form method=\"dialog\">\n <button type=\"submit\" class=\"text\" value=\"cancel\">Cancel</button>\n </form>\n</dialog>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `dialog-is-named`: A <dialog> takes no name from its heading. Point aria-labelledby at that heading, or give it an aria-label - otherwise it opens announced as just \"dialog\".\n- `drag-handle-is-hidden-or-a-control`: A drag handle has no text and reports nothing, so on any element but a <button> it is decoration and needs aria-hidden=\"true\". Left exposed it arrives as an unlabelled blank in the reading order. Make it a <button> with a name if it is meant to be operated.\n- `drag-handle-button-is-not-hidden`: aria-hidden on a <button> hides it from assistive technology without taking it out of the tab order, so keyboard focus lands on something that is not there. Decoration is a <span>; a control stays exposed.\n- `drag-handle-button-is-named`: The handle is a bar drawn in CSS - there is no text inside it to be named by. A handle worth making a control is worth an aria-label saying what it moves.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"file": "breadcrumbs.md",
|
|
24
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Breadcrumbs\nThe path to this page, from the HTML.\n\nComponent ID: `breadcrumbs`\n\n[Component documentation](https://www.expressivecss.com/breadcrumbs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/breadcrumbs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
24
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Breadcrumbs\nThe path to this page, from the HTML.\n\nComponent ID: `breadcrumbs`\n\n[Component documentation](https://www.expressivecss.com/breadcrumbs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/breadcrumbs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. No dedicated entry in the reviewed Google component inventory.\n\nExample: Overview/Activity/Billing are peers, not ancestors. Use tabs for their same-page panels, not a breadcrumb trail.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: none. Web extension; no dedicated entry was observed in the reviewed current M3 component inventory.\n\nUpstream: web-extension-inventory-reviewed (2026-09-13); [evidence](https://m3.material.io/components).\n\nRequirements and boundaries: design reference web-extensions-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-13, `llm.md#breadcrumbs`): Breadcrumb links and app-bar composition.\n\nWeb adaptation: Labelled navigation with an ordered list and current-page link.\n\nKnown boundary: Named navigation and current-page markup are checked; CSS separator speech and long-path reflow remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#breadcrumbs).\n\n#### Contract\n\nShow the current location when the page sits several layers deep.\n\nBreadcrumbs are a good way to display your current location. This is usually used when you have multiple layers of content.\n\n#### Syntax\n\n```html\n<nav aria-label=\"Breadcrumb\">\n <ol>\n <li><a href=\"/\">Home</a></li>\n <li><a href=\"/library\">Library</a></li>\n <li><a href=\"/library/data\" aria-current=\"page\">Data</a></li>\n </ol>\n</nav>\n```\n\n#### Also documented\n\nThe Breadcrumbs section of the [API reference](https://www.expressivecss.com/llm.md) also covers Basic, Navbar style.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `breadcrumb-is-ordered-list`: Crumbs are an ordered list - nav > ol > li > a. Loose anchors give no count and no position, so \"3 of 4\" is never announced.\n- `breadcrumb-marks-current`: The last crumb is the page you are on; it needs aria-current=\"page\" to say so.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"file": "button-groups.md",
|
|
28
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Button groups\nRelated buttons that bump and reshape against each other, in two variants and five sizes.\n\nComponent ID: `button-groups`\n\n[Component documentation](https://www.expressivecss.com/button-groups.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/button-groups.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
28
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Button groups\nRelated buttons that bump and reshape against each other, in two variants and five sizes.\n\nComponent ID: `button-groups`\n\n[Component documentation](https://www.expressivecss.com/button-groups.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/button-groups.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/button-groups/overview)\n\nExample: Standard groups fit Cut/Copy/Paste commands; connected groups fit toggle choices. A pressed button does not submit a radio value: use native inputs for form values, or explicitly integrate persistence.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Google recommends the connected button group instead of segmented buttons. Match toggle state, required selection and persistence explicitly; native form submission is not supplied by aria-pressed.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/button-groups/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/button-groups/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/button-groups/guidelines).\n\nSupport (2026-09-18, `llm.md#button-groups`): Standard and connected groups; commands and opt-in selection.\n\nWeb adaptation: Runtime coordinates neighboring widths and selection; CSS handles connected shapes.\n\nKnown boundary: Native zoom, spoken output and physical-device behavior remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#button-groups).\n\n#### Contract\n\nA Material 3 Expressive button group places related commands or toggle buttons in one visual cluster. The root is a `<div class=\"button-group\">`; direct children can be common buttons or `.icon-button` controls. `ButtonGroup` is initialized by `Expressive.AutoInit()` to coordinate standard press widths. Selection management is opt-in through `data-selection`.\n\nCommon buttons and icon buttons both inherit group sizing and participate in standard growth and connected shape morphing. Standard press growth is 15% of the item's measured width and is taken from its immediate neighbors, keeping the group's total width stable. An explicit size class on a child overrides the group size. Use a visible container style: filled, tonal, outlined, or elevated for common buttons; filled, tonal, or outlined for icon buttons. Material warns against text buttons and standard icon buttons in groups because their transparent containers hide the shape interaction.\n\nAction-group items are direct controls: a `<button>`, or an `<a class=\"button\" href>` when it navigates. Selection groups accept only native `<button type=\"button\">` children, each with `aria-pressed`. A wrapper loses the gap and connected corners. Every icon-only item carries its own accessible name because the icon is `aria-hidden`.\n\n#### Syntax\n\n```html\n<div class=\"button-group\" data-selection=\"multiple\" role=\"group\" aria-label=\"Text formatting\">\n <button type=\"button\" class=\"button tonal\" aria-pressed=\"false\">\n <span class=\"material-symbols\" aria-hidden=\"true\">format_bold</span>\n Bold\n </button>\n <button type=\"button\" class=\"button tonal\" aria-pressed=\"false\">\n <span class=\"material-symbols\" aria-hidden=\"true\">format_italic</span>\n Italic\n </button>\n</div>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `button-group-is-not-an-authored-composite-widget`: A button group takes no composite role; its buttons are reached with Tab, not arrow keys. `role=\"group\"` with an aria-label is the role that fits, and it promises no keyboard model.\n- `button-group-items-are-controls`: Every item in a group is a control the user can reach, and one the sheet styles as a button: a <button>, or an <a class=\"button\" href> when it navigates. A bare <a href> passes for a control and renders as a link - none of the group's corners, press behaviour or inherited size reach it. A wrapper element is refused too: the gap and the connected corners are written against direct children, so a nested <div> loses both.\n- `button-group-items-have-containers`: Material warns against text buttons in a group because they have no visible container for the shape interaction. Use filled, tonal, outlined, or elevated buttons.\n- `button-group-icon-items-have-containers`: Material warns against standard icon buttons in a group because they have no visible container for the shape interaction. Use a filled, tonal, or outlined icon button.\n- `button-group-selection-mode-is-valid`: ButtonGroup supports data-selection=\"single\" or data-selection=\"multiple\". Any other value exposes toggle state without a defined selection model.\n- `button-group-required-needs-selection`: data-selection-required only has meaning on a single- or multiple-selection ButtonGroup.\n- `button-group-connected-is-selectable`: Material connected button groups contain toggleable choices. Add data-selection=\"single|multiple\", or use the standard group for one-shot actions.\n- `button-group-selection-items-are-buttons`: Selection items are native buttons. Links navigate and cannot represent toggle-button state.\n- `button-group-selection-button-type`: A selection button inside a form must not submit it; set type=\"button\".\n- `button-group-selection-state-is-pressed`: Author each toggle button's initial aria-pressed value. ButtonGroup maintains that state after initialization.\n- `button-group-selection-state-is-boolean`: A toggle button's initial aria-pressed value is true or false; mixed is not a Button Group state.\n- `button-group-selection-does-not-use-choice-state`: These are toggle buttons, not radios, checkboxes, options, or tabs. Expose their state with aria-pressed.\n- `button-group-action-does-not-claim-selection`: aria-pressed requires ButtonGroup selection behavior. Add data-selection=\"single|multiple\" or remove the toggle state.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"file": "buttons.md",
|
|
32
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Buttons\nMaterial Design 3 common buttons, icon buttons, and FABs — from the HTML.\n\nComponent ID: `buttons`\n\n[Component documentation](https://www.expressivecss.com/buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
32
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Buttons\nMaterial Design 3 common buttons, icon buttons, and FABs — from the HTML.\n\nComponent ID: `buttons`\n\n[Component documentation](https://www.expressivecss.com/buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/buttons/overview)\n\nExample: Use radios for saved form values; buttons run commands.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Google no longer recommends 24dp padding for small buttons; use the current 16dp inset. This is spacing guidance, not removal of a button style.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/buttons/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/buttons/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/buttons/guidelines).\n\nSupport (2026-09-07, `llm.md#buttons`): Filled, tonal, outlined, elevated, and text; xsmall through xlarge.\n\nWeb adaptation: Native buttons run commands; a.button links navigate.\n\nKnown boundary: Standalone common buttons do not document a square/toggle shape-morph contract; do not borrow icon-button or connected-group modifiers.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#buttons).\n\n#### Contract\n\nMaterial Design 3 common buttons, icon buttons, and FABs — from the HTML.\n\nA `<button>` is a filled common button. An `<a class=\"button\">` is the same thing for a link — on an anchor the class is `button`; the older `.btn` spelling only ever worked on a `<button>`, which is styled as one anyway. Put a `<span class=\"material-symbols\" aria-hidden=\"true\">` icon before or after the label and wrap the label in its own `<span>` — there is no `icon-left` / `icon-right` class, the order of the two spans is the placement. Add `circle` for a round common button and name it with `aria-label`, since the icon is hidden. Icon buttons are `.icon-button`.\n\nTwo independent axes dress it: a style (`filled`, `tonal`, `outlined`, `elevated`, `text`) and a size (`xsmall` through `xlarge`). Any style combines with any size — nine classes, not twenty-five, because the size sets the geometry and the style sets the color.\n\n#### Syntax\n\n```html\n<button>Create</button>\n<button>\n <span class=\"material-symbols\" aria-hidden=\"true\">add</span><span>Create</span>\n</button>\n<button>\n <span>Send</span><span class=\"material-symbols\" aria-hidden=\"true\">send</span>\n</button>\n<button class=\"circle\" aria-label=\"Add\">\n <span class=\"material-symbols\" aria-hidden=\"true\">add</span>\n</button>\n\n<a class=\"button\" href=\"/docs\">Docs</a>\n```\n\n#### Also documented\n\nThe Buttons section of the [API reference](https://www.expressivecss.com/llm.md) also covers Filled, Tonal, Outlined, Elevated, Text, Icon buttons, Floating, Sizes, Disabled.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `icon-only-control-is-named`: Every icon is hidden from assistive technology, so a control whose only content is one has no name left. Give it an aria-label.\n- `fab-no-small-variant`: The 40dp small FAB has been removed. Use circle extra for a 56dp FAB.\n- `extended-fab-requires-size`: The baseline extended FAB has been removed. Specify extend small, extend medium or extend large.\n- `fab-no-surface-color`: Use a primary, secondary or tertiary container color for a FAB instead of a surface color.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"file": "cards.md",
|
|
36
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Cards\nMaterial Design 3 cards, from the HTML.\n\nComponent ID: `cards`\n\n[Component documentation](https://www.expressivecss.com/cards.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/cards.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
36
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Cards\nMaterial Design 3 cards, from the HTML.\n\nComponent ID: `cards`\n\n[Component documentation](https://www.expressivecss.com/cards.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/cards.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/cards/overview)\n\nExample: A hundred compact activity records need a list. Giving every row a card adds separation without a separate content or action group.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/cards/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/cards/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/cards/guidelines).\n\nSupport (2026-09-13, `llm.md#cards`): Elevated, filled, outlined, horizontal, and directly actionable cards.\n\nWeb adaptation: Native article anatomy; primary-action links preserve navigation semantics.\n\nKnown boundary: Existing card lifecycle and geometry evidence does not cover every selected variant, contrast and reflow state.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#cards).\n\n#### Contract\n\nMaterial Design 3 cards, from the HTML.\n\nAn `<article>` is an elevated card. Any heading is the headline, `<p class=\"subhead\">` is the optional subhead, a `<p>` is supporting copy, direct `<img>`, `<picture>`, or `<figure>` is media, and direct `<div class=\"actions\">` is the action row. Include only the slots the content needs. There is no `card-content`, `card-title`, `card-action`, `card` or `card-panel` class—the element is the component, and the action row is not a `<nav>`. Tokens follow the [M3 card spec](https://m3.material.io/components/cards/specs): all variants use 12dp corners; elevated rests at level 1, filled and outlined at level 0. A directly actionable card wraps its primary content in one direct `a.primary-action[href]` and has no second link or control. Horizontal cards preserve that source order, use content height with a 240px minimum unless a size helper fixes the expanded height, and stack below 600px with fixed heights reset to content. During reordering, `.dragged` or `.picked-up` preserves the 16% state layer and dragged elevation while the primary action remains hovered or pressed.\n\nA Card reveal is a disclosure with exactly one identified direct `<aside>` and an enabled, accessibly named `button.card-reveal-trigger[type=\"button\"]` outside that panel. Its `aria-controls` must resolve to the panel, and its closest `<article>` owns it—even when a complete nested card sits inside an outer reveal panel. After accepting the contract, Cards writes `aria-expanded`, marks the closed panel `inert`, closes it with Escape, and returns focus from the panel to the trigger. Rejected, disabled-only, unidentified, and multi-panel disclosures remain visible and unmanaged.\n\n#### Syntax\n\n```html\n<article>\n <header>\n <h3>Weekend in the mountains</h3>\n <p class=\"subhead\">Three-day itinerary</p>\n </header>\n <p>Explore trails and overlooks.</p>\n <img src=\"images/mountains.jpg\" alt=\"Mountain valley beneath a cloudy sky\">\n <div class=\"actions\">\n <button type=\"button\" class=\"text\">Share</button>\n <button type=\"button\" class=\"tonal\">View trip</button>\n </div>\n</article>\n```\n\n#### Also documented\n\nThe Cards section of the [API reference](https://www.expressivecss.com/llm.md) also covers Variants, Primary action and states, Collections, Media, Horizontal, Reveal, Expanding card, Sizes.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `card-action-row-not-nav`: Cards do not contain navigation or tabs. Put navigation outside the card and use <div class=\"actions\"> for its action buttons.\n- `card-primary-action-is-control`: A directly actionable card uses one native link as its primary action. Use the action row for commands; common button styles do not turn a button into the card container.\n- `card-disabled-link-has-no-href`: A disabled card destination must not retain href. aria-disabled does not stop a link from navigating when activated from the keyboard.\n- `card-disabled-link-not-tabbable`: A disabled card destination is not operable, so remove it from the tab order with tabindex=\"-1\".\n- `card-primary-action-is-only-action`: A directly actionable card contains no second action. Use one primary-action link, or make the card non-actionable and put its controls in the action row.\n- `card-primary-action-is-single`: A directly actionable card has exactly one direct primary-action link. Remove duplicate primary actions or use a non-actionable card with an action row.\n- `card-reveal-has-trigger`: A card with a direct reveal panel requires a native card-reveal-trigger button whose closest article is that card and which sits outside the reveal panel.\n- `card-reveal-has-one-panel`: A card reveal has exactly one direct aside panel. With multiple direct panels, Cards rejects disclosure setup and every panel remains visible and unmanaged.\n- `card-reveal-trigger-is-button`: The reveal trigger is a native button so Enter, Space, disabled state, and focus work without synthetic keyboard handling.\n- `card-reveal-trigger-type-button`: A card reveal button may appear inside a form, so set type=\"button\" to prevent accidental submission.\n- `card-reveal-trigger-has-label`: The reveal button needs a non-empty accessible name describing the details it toggles; icon-only triggers should use aria-label.\n- `card-reveal-trigger-controls-panel`: Name the reveal panel from aria-controls so assistive technology can relate the disclosure button to its content.\n- `card-reveal-panel-has-id`: The reveal panel needs the id referenced by its trigger's aria-controls.\n- `card-reveal-expanded-is-not-authored`: Cards writes aria-expanded on the disclosure button. Do not author a stale initial value, and do not put aria-expanded on the panel.\n- `expanding-card-trigger-is-button`: The media-sized trigger opens a dialog, so use a button for native keyboard and disabled behavior.\n- `expanding-card-close-is-button`: The back affordance closes the expanded surface, so use a button for native keyboard behavior.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"file": "carousel.md",
|
|
40
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Carousel\nMaterial 3 adaptive carousels for visual collections.\n\nComponent ID: `carousel`\n\n[Component documentation](https://www.expressivecss.com/carousel.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/carousel.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
40
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Carousel\nMaterial 3 adaptive carousels for visual collections.\n\nComponent ID: `carousel`\n\n[Component documentation](https://www.expressivecss.com/carousel.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/carousel.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/carousel/overview)\n\nExample: A transaction history must support scanning rows and values. Use a list instead of hiding records across carousel slides.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/carousel/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/carousel/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/carousel/guidelines).\n\nSupport (2026-09-17, `llm.md#carousel`): Adaptive visual collections with documented layout variants.\n\nWeb adaptation: Runtime owns sizing and navigation; reduced motion removes parallax and morphing.\n\nKnown boundary: Rendered navigation and application-owned pause controls have browser coverage; screen readers, native zoom and physical-device review remain pending.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#carousel).\n\n#### Contract\n\nA Material 3 adaptive carousel for visual collections.\n\nThe default is multi-browse: one large, one medium, and one small item adapt as the active item changes. `AutoInit()` starts every `.carousel` except those marked `no-autoinit`. Give the container an accessible name and every direct item the `carousel-item` class.\n\n#### Syntax\n\n```html\n<div class=\"carousel\" aria-label=\"Featured landscapes\">\n <a class=\"carousel-item\" href=\"mountain-lake.html\">\n <img src=\"images/mountain-lake.jpg\" alt=\"Mountain lake\">\n <span class=\"carousel-item-content\">Mountain lake</span>\n </a>\n <a class=\"carousel-item\" href=\"forest-path.html\">\n <img src=\"images/forest-path.jpg\" alt=\"Forest path\">\n <span class=\"carousel-item-content\">Forest path</span>\n </a>\n <a class=\"carousel-item\" href=\"rocky-coastline.html\">\n <img src=\"images/rocky-coastline.jpg\" alt=\"Rocky coastline\">\n <span class=\"carousel-item-content\">Rocky coastline</span>\n </a>\n</div>\n<div class=\"mt-1\"><a class=\"button text\" href=\"all-landscapes.html\">Show all</a></div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `duration` | Number | `200` | Milliseconds allowed for a programmatic scroll to land, and the part of each auto-advance rest that is not `interval`. |\n| `fullWidth` | Boolean | `false` | Full-width compatibility layout used by swipeable tabs. Prefer an M3 layout class for new carousels. |\n| `indicators` | Boolean | `false` | Legacy paging dots. M3 recommends a nearby Show all path instead of overlay controls. |\n| `noWrap` | Boolean | `false` | Stop auto-advance at the last item instead of looping back to the first. Arrow keys and `set()` stop at the ends either way — a scroll track has ends. |\n| `interval` | Number | `0` | Milliseconds to rest between automatic advances, on top of `duration`; a full cycle takes `duration + interval`. `0` leaves auto-advance off. Each rest is armed by the move before it rather than on a fixed phase. |\n| `height` | Number | `null` | Fixed track height in pixels. `null` sizes the carousel from its content. |\n| `onCycleTo` | Function | `null` | Called when the active item changes. |\n| `i18n` | Object | `{ carousel: 'Carousel', item: 'Item', of: 'of', indicators: 'Slides', slide: 'Slide' }` | Generated accessible label strings. `indicators` names the indicator row and `slide` prefixes each dot, giving \"Slide 1\". Partial objects are merged with the defaults. |\n\n#### Methods\n\n`next()` and `prev()` move one item or an optional item count. `set(index, callback)` moves to a zero-based item index. `pause()` and `start()` stop and resume auto-advance, and do nothing without an `interval`. `destroy()` removes generated labels, size roles, indicators, listeners, the scroll-track wrapper, and the auto-advance timer.\n\nAn `interval` makes the carousel advance on its own, so the pause contract is mandatory: it always pauses on hover, on focus within, and while the tab is hidden, and `prefers-reduced-motion: reduce` suppresses auto-advance entirely. No option disables any of that. An explicit `noWrap: true` stops auto-advance after one pass instead of looping. Arrow keys and `set()` stop at the ends either way — a scroll track has ends, and auto-advance is the one caller that can loop back past them. A `height` gives the indicators their own row below the track (`.fixed-height`) instead of laying them over the media; markup can do the same by carrying `.fixed-height` and setting `--carousel-height`.\n\n#### Also documented\n\nThe Carousel section of the [API reference](https://www.expressivecss.com/llm.md) also covers Layouts, Tokens, Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `hidden-subtree-holds-nothing-focusable`: Hidden from assistive technology but still in the tab order: focus lands on a control the user has no way to perceive. Take away the tab stop (tabindex=\"-1\"), or mark the subtree inert when it is genuinely not displayed - inert also removes it from hit-testing, which is wrong for anything still visible.\n- `carousel-not-a-composite-widget`: A carousel takes no composite role; it is a group of slides with independent controls.\n- `carousel-indicators-are-not-tabs`: Carousel indicators are independent controls, not tabs.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"file": "checkboxes.md",
|
|
44
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Checkboxes\nMaterial Design 3 checkboxes, from the HTML.\n\nComponent ID: `checkboxes`\n\n[Component documentation](https://www.expressivecss.com/checkboxes.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/checkboxes.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
44
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Checkboxes\nMaterial Design 3 checkboxes, from the HTML.\n\nComponent ID: `checkboxes`\n\n[Component documentation](https://www.expressivecss.com/checkboxes.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/checkboxes.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/checkbox/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/checkbox/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/checkbox/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/checkbox/guidelines).\n\nSupport (2026-09-13, `llm.md#checkboxes`): Unchecked, checked, indeterminate, and disabled.\n\nWeb adaptation: Native checkbox; indeterminate is set through the DOM property.\n\nKnown boundary: Native state coverage does not verify parent aggregation or every target and forced-colors state.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#checkboxes).\n\n#### Contract\n\nMaterial Design 3 checkboxes, from the HTML.\n\nA `<label>` wrapping `<input type=\"checkbox\">` is the control. The label text is a sibling of the input — no extra class, no required `<span>`. They are CSS only. There is no JavaScript component and nothing to AutoInit.\n\nTokens follow the [M3 checkbox spec](https://m3.material.io/components/checkbox/specs). The container is 18dp with 2dp corners. Unselected is a 2dp `on-surface-variant` outline. Selected is a `primary` fill with an `on-primary` check. Indeterminate is the same fill with a dash. The state layer is 40dp at 8% hover and 10% focus. The touch target is 48dp. The label is `body-large` / `on-surface`. Disabled is 38%.\n\n#### Syntax\n\n```html\n<label>\n <input type=\"checkbox\">\n Red\n</label>\n<label>\n <input type=\"checkbox\" checked>\n Yellow\n</label>\n<label>\n <input type=\"checkbox\" disabled>\n Brown\n</label>\n```\n\n#### Also documented\n\nThe Checkboxes section of the [API reference](https://www.expressivecss.com/llm.md) also covers In a row, Error.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `checkbox-labelled`: A checkbox must be inside its <label> or carry an id a label points at.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"file": "chips.md",
|
|
48
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Chips\nSmall blocks for contacts, tags, and filters.\n\nComponent ID: `chips`\n\n[Component documentation](https://www.expressivecss.com/chips.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/chips.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
48
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Chips\nSmall blocks for contacts, tags, and filters.\n\nComponent ID: `chips`\n\n[Component documentation](https://www.expressivecss.com/chips.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/chips.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/chips/overview)\n\nExample: A passive unread count is a badge. Turning it into a filter chip falsely suggests a selectable state unless filtering is implemented.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/chips/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/chips/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/chips/guidelines).\n\nSupport (2026-09-13, `llm.md#chips`): Assist, suggestion, filter, input, and display chips.\n\nWeb adaptation: Element choice defines behavior; display chips are a framework extension.\n\nKnown boundary: Rendered deletion, focus recovery and wrapped action/delete controls are checked. Full effective-target sizing, spoken output and physical-device behavior remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#chips).\n\n#### Contract\n\nSmall blocks for contacts, tags, and filters.\n\nA chip is a `.chip`, and **the element says which kind it is** — the four Material 3 chip types, plus a non-interactive display chip, across three root elements. Add `outlined` for a bordered style. Static chips are CSS. The JavaScript plugin lives on a `.chips` wrapper.\n\nA long label wraps and the chip grows from its 32dp minimum, with 4dp above and below the lines. It never grows wider than its parent.\n\n#### Syntax\n\n```html\n<span class=\"chip outlined\">Information</span>\n\n<span class=\"chip\">\n <img src=\"photo.jpg\" alt=\"\"> Jane Doe\n</span>\n\n<button type=\"button\" class=\"chip\">\n <span class=\"material-symbols\" aria-hidden=\"true\">event</span>\n Add to calendar\n</button>\n\n<input type=\"checkbox\" class=\"chip-input\" id=\"filter-flights\">\n<label class=\"chip\" for=\"filter-flights\">\n <span class=\"material-symbols\" aria-hidden=\"true\">check</span>\n Flights\n</label>\n\n<span class=\"chip\">\n Tag\n <button type=\"button\" class=\"close\" aria-label=\"Remove Tag\">\n <span class=\"material-symbols\" aria-hidden=\"true\">close</span>\n </button>\n</span>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `data` | Array | `[]` | Initial chips. Each item is a chip data object. |\n| `placeholder` | String | `''` | Placeholder when there are no chips. Requires `allowUserInput`. |\n| `secondaryPlaceholder` | String | `''` | Placeholder after at least one chip exists. |\n| `closeIconClass` | String | `'material-symbols'` | Class on the icon inside the delete button. |\n| `allowUserInput` | Boolean | `false` | If true, render a text field and a delete button per chip, so the user can add and remove chips. |\n| `i18n` | Object | `{ remove: 'Remove' }` | Strings the component generates. `remove` prefixes the delete button's accessible name, giving \"Remove Apple\". |\n| `autocompleteOptions` | Object | `{}` | Options passed to Autocomplete on the input. A non-empty object enables autocomplete. |\n| `autocompleteOnly` | Boolean | `false` | If true, Enter will not add a value that is not in the autocomplete list. |\n| `limit` | Number | `Infinity` | Maximum number of chips. |\n| `onChipAdd` | Function | `null` | Called after a chip is added. Receives the container and the chip element. |\n| `onChipSelect` | Function | `null` | Called when a chip is selected. Receives the container and the chip element. |\n| `onChipDelete` | Function | `null` | Called after a chip is deleted. Receives the container and the chip element. |\n\n#### Methods\n\n- `.addChip()`: Add a chip, including when `allowUserInput` is false. Numeric id `0` is valid. Ignored if `id` is missing, already present, or the limit is reached.\n- `.deleteChip()`: Delete the chip at this index.\n- `.selectChip()`: Focus the chip at this index.\n- `.getData()`: The current chips as an array of chip data objects.\n- `.destroy()`: Destroy the plugin instance, remove rendered chips, and tear down its event handlers. This also destroys the owned Autocomplete and its Menu.\n\n#### Also documented\n\nThe Chips section of the [API reference](https://www.expressivecss.com/llm.md) also covers Contacts, Tags, Javascript Plugin, Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `chip-root-element`: A chip is <span> (display), <button> (assist/suggestion/input), or <label> (filter). Never <div>.\n- `chip-not-focusable-span`: A display chip is not a control and must not be in the tab order. Put the action on a nested <button>.\n- `chip-close-is-button`: The chip delete affordance is a control: use <button type=\"button\" class=\"close\">, not <i> or <span>.\n- `chip-close-type-button`: A <button> inside a form defaults to type=submit. Chip delete buttons must set type=\"button\".\n- `chip-close-has-label`: The delete button contains only an icon, so it needs an accessible name naming the chip it removes.\n- `chip-no-i-element`: <i> means idiomatic text, not icon. Use <span class=\"material-symbols\" aria-hidden=\"true\">.\n- `chip-icon-hidden`: A ligature icon is read aloud verbatim. Decorative icons inside a labelled control must be aria-hidden.\n- `filter-chip-label-for`: A filter chip is <input type=\"checkbox\"> + <label class=\"chip\">; the label must point at its input.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"file": "date-picker.md",
|
|
52
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Date picker\nSelect a date, a range, or several dates from a calendar.\n\nComponent ID: `date-picker`\n\n[Component documentation](https://www.expressivecss.com/datepicker.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/datepicker.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
52
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Date picker\nSelect a date, a range, or several dates from a calendar.\n\nComponent ID: `date-picker`\n\n[Component documentation](https://www.expressivecss.com/datepicker.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/datepicker.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/date-pickers/overview)\n\nExample: A single date with no calendar-specific requirements can use a labeled native date input. Do not choose this picker expecting a popup: its calendar is inline and requires the documented visibility option.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/date-pickers/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/date-pickers/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/date-pickers/guidelines).\n\nSupport (2026-09-17, `llm.md#date-picker`): Inline single-date, range, and multiple-date calendar.\n\nWeb adaptation: Default inline presentation with optional docked display plugin; no open()/close() methods or modal implementation.\n\nKnown boundary: Modal picker parity is not provided by the documented inline API.\n\nKnown boundary: Calendar keyboard navigation and range/multiple selection lifecycle have browser coverage. Spoken calendar context, native zoom and physical devices remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#date-picker).\n\n#### Contract\n\nSelect a date, a range, or several dates from a calendar.\n\nAdd `date-picker` to a text input. `AutoInit()` starts every `.date-picker` except those marked `no-autoinit`.\n\nThe calendar is inline, not a modal. `open()` and `close()` are not provided. With the default options the calendar is hidden (`openByDefault: false`) and clicking the input does not reveal it. Pass `openByDefault: true` to show the calendar under the field.\n\n#### Syntax\n\n```html\n<div class=\"field\">\n <input type=\"text\" class=\"date-picker\" id=\"birthdate\">\n <label for=\"birthdate\">Birthdate</label>\n</div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `format` | String or Function | `'mmm dd, yyyy'` | Output written to the input, or a function that takes a `Date` and returns a string. |\n| `parse` | Function | `null` | Turn the current input string back into a `Date`. Receives `(value, format)`, where `format` is the configured string or an empty string for a function formatter. Blank inputs skip parsing. |\n| `isDateRange` | Boolean | `false` | Select a start date and an end date. |\n| `dateRangeEndEl` | String | `null` | Selector for an existing end-date input. If omitted, a second input is created. |\n| `isMultipleSelection` | Boolean | `false` | Toggle several dates. Extra inputs are created as dates are added. |\n| `defaultDate` | Date | `null` | Initial date to view. Falls back to the input’s current value, then today. |\n| `defaultEndDate` | Date | `null` | Initial end date when `isDateRange` is true. |\n| `setDefaultDate` | Boolean | `false` | If true, `defaultDate` is also the selected value. |\n| `setDefaultEndDate` | Boolean | `false` | If true, `defaultEndDate` is also the selected end value. |\n| `disableWeekends` | Boolean | `false` | Prevent selecting Saturday and Sunday. |\n| `disableDayFn` | Function | `null` | Return true to disable that day. Receives a `Date`. |\n| `firstDay` | Number | `0` | First day of the week. `0` is Sunday, `1` is Monday. |\n| `minDate` | Date | `null` | Earliest selectable date. |\n| `maxDate` | Date | `null` | Latest selectable date. |\n| `yearRange` | Number or Array | `10` | Years on either side of the viewed year, or `[minYear, maxYear]`. |\n| `yearRangeReverse` | Boolean | `false` | Sort the year list in reverse order. |\n| `isRTL` | Boolean | `false` | Render the calendar right-to-left. |\n| `showMonthAfterYear` | Boolean | `false` | Show the month after the year in the title. |\n| `showDaysInNextAndPreviousMonths` | Boolean | `false` | Render days that fall in the adjoining months. |\n| `openByDefault` | Boolean | `false` | If true, the calendar is visible. If false, it is given `display: none`. |\n| `container` | Element or String | `null` | Element or selector to render the calendar into. When set, the calendar is not hidden. |\n| `showClearBtn` | Boolean | `false` | Show a Clear button in the footer. |\n| `autoSubmit` | Boolean | `true` | If true, selecting a day writes the input immediately. If false, Ok and Cancel buttons are added. |\n| `i18n` | Object | See below | Labels and month/weekday names. Partial objects are merged with the defaults. |\n| `events` | Array | `[]` | Strings from `Date.toDateString()`. Matching days get a `has-event` class. The default stylesheet does not style that class. |\n| `onSelect` | Function | `null` | Called when a date is selected. Receives the `Date`. |\n| `onDraw` | Function | `null` | Called after the calendar HTML is redrawn. |\n| `onInputInteraction` | Function | `null` | Called when the input is clicked or confirmed with Enter. |\n| `onConfirm` | Function | `null` | Called once when Ok is activated by click, Enter or Space. The button is created when `autoSubmit` is false. |\n| `onCancel` | Function | `null` | Called once when Cancel is activated by click, Enter or Space. The button is created when `autoSubmit` is false. |\n| `displayPlugin` | String | `null` | Set to `'docked'` for a click-to-open popover. Pair with `openByDefault: true`. |\n| `displayPluginOptions` | Object | `null` | Options for the docked plugin: `margin`, `transition`, `duration`, `align`. |\n\n#### Methods\n\n- `.toString()`: String form of the selected date, using `format`. You can pass another date and format.\n- `.setDate()`: Select a date and move the calendar to it.\n- `.gotoDate()`: Change the visible month without changing the selection.\n- `.destroy()`: Destroy the plugin instance, remove the calendar, and tear down its event handlers.\n- `.open(); / .close()`: These methods are not provided. The calendar defaults to inline presentation; `displayPlugin: 'docked'` enables docking. Both require `openByDefault: true` to show the calendar. No modal implementation is available.\n\n#### Also documented\n\nThe Date Picker section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Display, Date format options, Internationalization, Calendar keyboard navigation, Date range, Multiple dates, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\nNo component-specific `semantics.json` rules apply to this guide.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"file": "dialogs.md",
|
|
56
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Dialogs\nImportant prompts in a user flow. Dedicated to a single task.\n\nComponent ID: `dialogs`\n\n[Component documentation](https://www.expressivecss.com/dialogs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/dialogs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
56
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Dialogs\nImportant prompts in a user flow. Dedicated to a single task.\n\nComponent ID: `dialogs`\n\n[Component documentation](https://www.expressivecss.com/dialogs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/dialogs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `shared-runtime`. [Google guidance](https://m3.material.io/components/dialogs/overview)\n\nExample: Saving successfully should not force dismissal of a dialog. Use a snackbar for that feedback and inline feedback for a persistent nonblocking issue; reserve a confirmation dialog for a decision that must precede the action.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/dialogs/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/dialogs/specs); full specs unreviewed.\n\nSupport (2026-09-07, `llm.md#dialogs`): Basic and full-screen dialogs.\n\nWeb adaptation: Native dialog.showModal()/close(); shared dialog behavior is separate from AutoInit.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#dialogs).\n\n#### Contract\n\nMaterial Design 3 dialogs, from the HTML.\n\nA `<dialog>` is a basic dialog. A heading is the headline, a `<p>` (or a wrapping `<div>`) is supporting text, and the last child `<form method=\"dialog\">` or `<nav>` is the action row. `dialog.max` is the full-screen variant. There are no `.modal`, `modal-header`, `modal-content`, or `modal-footer` classes — the element is the component.\n\nTokens follow the [M3 dialog spec](https://m3.material.io/components/dialogs/specs). The container is `surface`, 28dp corners, 280–560dp wide, elevation 3. The headline is `headline-small` / `on-surface`; supporting text is `body-medium`. The scrim is `--md-comp-scrim-color`. Actions sit at the end with an 8dp gap.\n\n#### Syntax\n\n```html\n<button type=\"button\" onclick=\"document.getElementById('dialog1').showModal()\">\n Show\n</button>\n\n<dialog id=\"dialog1\" aria-labelledby=\"use-location-services-title\">\n <h2 id=\"use-location-services-title\">Use location services?</h2>\n <p>Let the app use your location to suggest nearby stops.</p>\n <form method=\"dialog\">\n <button type=\"submit\" class=\"text\" value=\"disagree\">Disagree</button>\n <button type=\"submit\" value=\"agree\">Agree</button>\n </form>\n</dialog>\n```\n\n#### Methods\n\n- `.showModal()`: Open as a modal, with the scrim.\n- `.close()`: Close the dialog.\n\n#### Also documented\n\nThe Dialogs section of the [API reference](https://www.expressivecss.com/llm.md) also covers Tokens, Full-screen.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `dialog-is-named`: A <dialog> takes no name from its heading. Point aria-labelledby at that heading, or give it an aria-label - otherwise it opens announced as just \"dialog\".\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"file": "drag-handle.md",
|
|
60
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Drag handle\nThe bar that says a thing can be dragged — and nothing that does the dragging.\n\nComponent ID: `drag-handle`\n\n[Component documentation](https://www.expressivecss.com/drag-handle.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/drag-handle.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
60
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Drag handle\nThe bar that says a thing can be dragged — and nothing that does the dragging.\n\nComponent ID: `drag-handle`\n\n[Component documentation](https://www.expressivecss.com/drag-handle.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/drag-handle.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Related Google guidance](https://m3.material.io/components/bottom-sheets/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: related. Related guidance is not a dedicated component specification.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/bottom-sheets/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/bottom-sheets/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/bottom-sheets/guidelines).\n\nSupport (2026-09-13, `llm.md#drag-handle`): Decorative grip and actionable button grip.\n\nWeb adaptation: The host element determines semantics; no general dragging engine.\n\nKnown boundary: A grip outside supported sheets implements neither dragging nor keyboard or non-drag pointer alternatives.\n\nKnown boundary: Standalone grip styling supplies no drag, resize or reorder operation.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#drag-handle).\n\n#### Contract\n\nThe bar that makes something legible as draggable: a bottom sheet's grabber, the gutter between two panes, the grip on a reorderable row.\n\nWhich element you write *is* the semantic. A `<span class=\"drag-handle\" aria-hidden=\"true\">` is decoration and is the usual case — the handle draws a bar and contains no text, so exposed it arrives in the reading order as an unlabelled blank. A `<button class=\"drag-handle\">` with an `aria-label` is a control, written only when activating it does something — inside a bottom sheet it always does, and everywhere else that is the page's to arrange. Never `aria-hidden` a button: that hides it from assistive technology without taking it out of the tab order. The hover, focus and pressed states are scoped to the button spelling, so a decorative handle does not light up under a passing pointer.\n\n**Nothing here drags.** No script belongs to this component and ExpressiveCSS ships no reordering behaviour. The one thing a handle is wired to is the bottom sheet's, below. Provide both keyboard operation and a single-pointer alternative without dragging, such as clickable \"Move up\" / \"Move down\" buttons or a position input. Arrow keys alone cover only the keyboard path. [WCAG 2.2 SC 2.5.7](https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html) requires the pointer alternative unless dragging is essential or the unmodified user agent owns the functionality. Verify the alternatives independently; the handle does not implement either one.\n\n#### Syntax\n\n```html\n<section aria-label=\"Editor\">…</section>\n<span class=\"drag-handle\" aria-hidden=\"true\"></span>\n<section aria-label=\"Preview\">…</section>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `drag-handle-is-hidden-or-a-control`: A drag handle has no text and reports nothing, so on any element but a <button> it is decoration and needs aria-hidden=\"true\". Left exposed it arrives as an unlabelled blank in the reading order. Make it a <button> with a name if it is meant to be operated.\n- `drag-handle-button-is-not-hidden`: aria-hidden on a <button> hides it from assistive technology without taking it out of the tab order, so keyboard focus lands on something that is not there. Decoration is a <span>; a control stays exposed.\n- `drag-handle-button-is-named`: The handle is a bar drawn in CSS - there is no text inside it to be named by. A handle worth making a control is worth an aria-label saying what it moves.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"file": "fab.md",
|
|
64
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Floating action button\nA circular action that can open a menu of related shortcuts.\n\nComponent ID: `fab`\n\n[Component documentation](https://www.expressivecss.com/floating-action-button.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/floating-action-button.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
64
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Floating action button\nA circular action that can open a menu of related shortcuts.\n\nComponent ID: `fab`\n\n[Component documentation](https://www.expressivecss.com/floating-action-button.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/floating-action-button.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/floating-action-button/overview)\n\nExample: Speed dials have been removed. Replace legacy fab or fixed-action-btn wrappers with fab-menu and labelled actions; use a toolbar for persistent commands.\n\n- expanded window: variant. Use the extended FAB when the action benefits from a visible label.\n\n#### Material mapping\n\nRelationship: component. Google no longer recommends small FABs, baseline extended FABs or surface-colored FABs. The 40dp FAB and sizeless extend variant are removed. Use circle extra for the 56dp FAB, or its medium and large sizes. Extended FABs require extend small, extend medium or extend large; the small extended FAB remains recommended. Use primary/secondary/tertiary container roles instead of surface colors. Use fab-menu for labelled related actions; speed-dial APIs are removed.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/floating-action-button/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/floating-action-button/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/floating-action-button/guidelines).\n\n[Related Google component](https://m3.material.io/components/extended-fab/overview).\n\n[Related Google component](https://m3.material.io/components/fab-menu/overview).\n\nSupport (2026-09-13, `llm.md#floating-action-button`): FAB sizes, extended FABs, and menus of related actions.\n\nWeb adaptation: Floating action behavior uses the documented FAB runtime.\n\nKnown boundary: Full visual parity and spoken assistive-technology output remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#fab).\n\n#### Contract\n\nUse a standalone FAB for the primary action or a FAB menu for related labelled actions.\n\n`fab-menu` is the FAB that expands into a list of labelled actions. The trigger is an ordinary FAB; the actions are a `<ul>` (or `<menu>`) of pills, each an icon and a label at 56dp on a full corner. Click the FAB to expand; click it again, click outside, or press Escape to collapse.\n\nExpanded is the framework's state, not the author's: the constructor stamps `aria-expanded` on the trigger and `open()` / `close()` move it along with the `active` class. Do not write either into the markup.\n\n#### Syntax\n\n```html\n<div class=\"fab-menu\">\n <button type=\"button\" class=\"button extra circle\" aria-label=\"Create\">\n <span class=\"material-symbols\" aria-hidden=\"true\">add</span>\n <span class=\"material-symbols\" aria-hidden=\"true\">close</span>\n </button>\n <ul>\n <li><button type=\"button\"><span class=\"material-symbols\" aria-hidden=\"true\">mode_edit</span><span>Compose</span></button></li>\n <li><button type=\"button\"><span class=\"material-symbols\" aria-hidden=\"true\">image</span><span>Add photo</span></button></li>\n </ul>\n</div>\n```\n\n#### Methods\n\n- `.open()`: Opens the FAB menu.\n- `.close()`: Closes the FAB menu.\n- `.destroy()`: Destroy the plugin instance and tear down its event handlers.\n\n#### Also documented\n\nThe Floating Action Button section of the [API reference](https://www.expressivecss.com/llm.md) also covers FAB menu, Initialization, Properties, Speed-dial migration.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `icon-only-control-is-named`: Every icon is hidden from assistive technology, so a control whose only content is one has no name left. Give it an aria-label.\n- `fab-no-small-variant`: The 40dp small FAB has been removed. Use circle extra for a 56dp FAB.\n- `extended-fab-requires-size`: The baseline extended FAB has been removed. Specify extend small, extend medium or extend large.\n- `fab-no-surface-color`: Use a primary, secondary or tertiary container color for a FAB instead of a surface color.\n- `fab-menu-not-a-composite-widget`: The FAB menu takes no composite role; its actions are reached with Tab, not arrow keys.\n- `fab-menu-expanded-is-not-authored`: Expanded is dynamic state, so the framework owns it. The constructor stamps aria-expanded on the trigger and every open() and close() rewrites it; authoring it states a value that is about to be overwritten.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"file": "fieldsets.md",
|
|
68
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Fieldsets\nGrouped form sections, from the HTML.\n\nComponent ID: `fieldsets`\n\n[Component documentation](https://www.expressivecss.com/fieldsets.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/fieldsets.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
68
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Fieldsets\nGrouped form sections, from the HTML.\n\nComponent ID: `fieldsets`\n\n[Component documentation](https://www.expressivecss.com/fieldsets.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/fieldsets.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Related Google guidance](https://m3.material.io/components/text-fields/overview)\n\nExample: A promotional feature block needs a section or card. Use a fieldset when a shared legend explains related inputs, such as delivery preferences.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: related. Related guidance is not a dedicated component specification.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/text-fields/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/text-fields/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/text-fields/guidelines).\n\nSupport (2026-09-13, `llm.md#fieldsets`): Outlined, filled, and rounded form groups.\n\nWeb adaptation: Native fieldset/legend; related text-field tokens do not make this an M3 component.\n\nKnown boundary: Named native groups and disabled descendants are checked; long legends and nested groups remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#fieldsets).\n\n#### Contract\n\nGrouped form sections, from the HTML.\n\nA `<fieldset>` is the group. A `<legend>` is the headline. Everything else is a field — `.field`, radios, switches, a `.inline` row of radios, a trailing `<small>` as supporting text. There is no wrapper class. They are CSS only. There is no JavaScript component and nothing to AutoInit.\n\nMaterial Design 3 has no fieldset component. Tokens follow the outlined grouping container used around related form content, and the [outlined text-field](https://m3.material.io/components/text-fields/specs) shape so a group of fields matches the fields. The container is 4dp corners and a 1dp `outline-variant` stroke. The legend is `title-small` / `on-surface`. Supporting text is `body-small`. Padding is 16dp; children sit 16dp apart. Disabled is 38%.\n\n#### Syntax\n\n```html\n<fieldset>\n <legend>Name</legend>\n <div class=\"field\">\n <input id=\"first\" type=\"text\" placeholder=\" \">\n <label for=\"first\">First name</label>\n </div>\n <div class=\"field\">\n <input id=\"last\" type=\"text\" placeholder=\" \">\n <label for=\"last\">Last name</label>\n </div>\n</fieldset>\n```\n\n#### Also documented\n\nThe Fieldsets section of the [API reference](https://www.expressivecss.com/llm.md) also covers Choices, Variants, Disabled.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `fieldset-has-legend`: A fieldset without a legend groups controls visually but names nothing.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"file": "footer.md",
|
|
72
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Footer\nSite navigation and extra information at the end of a page.\n\nComponent ID: `footer`\n\n[Component documentation](https://www.expressivecss.com/footer.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/footer.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
72
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Footer\nSite navigation and extra information at the end of a page.\n\nComponent ID: `footer`\n\n[Component documentation](https://www.expressivecss.com/footer.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/footer.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. No dedicated entry in the reviewed Google component inventory.\n\nExample: Home/Search/Profile should not require scrolling to a footer. Use a navigation bar or rail for those destinations.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: none. Web extension; no dedicated entry was observed in the reviewed current M3 component inventory.\n\nUpstream: web-extension-inventory-reviewed (2026-09-13); [evidence](https://m3.material.io/components).\n\nRequirements and boundaries: design reference web-extensions-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-13, `llm.md#footer`): Native footer with navigation columns and copyright content.\n\nWeb adaptation: Web page landmark styled with theme roles.\n\nKnown boundary: A document-level contentinfo landmark is checked; section-scoped footers and responsive legal links remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#footer).\n\n#### Contract\n\nSite navigation and extra information at the end of a page.\n\nFooters are a good place for site navigation and extra information. This is where people look after they finish the page, or when they want more about the site.\n\nPut the page in the three HTML5 landmarks `header`, `main`, and `footer`. Anatomy is the HTML: a bare `<footer>` is the component, each `<nav>` is a column of links with an `<h2>` heading, and a trailing `<small>` is the copyright bar. There is no `page-footer` or `footer-copyright` class, and no JavaScript component.\n\n#### Syntax\n\n```html\n<footer>\n <section>\n <h2>Product</h2>\n <p>A column with no links is not navigation — it is a section with a heading.</p>\n </section>\n <nav aria-labelledby=\"footer-links\">\n <h2 id=\"footer-links\">Links</h2>\n <a href=\"/about\">About</a>\n <a href=\"/contact\">Contact</a>\n </nav>\n <small>\n <span>© 2026 Copyright Text</span>\n <a href=\"/privacy\">Privacy</a>\n </small>\n</footer>\n```\n\n#### Also documented\n\nThe Footer section of the [API reference](https://www.expressivecss.com/llm.md) also covers Sticky Footer.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `footer-nav-has-links`: A footer column with no links is not navigation - it is a <section> with a heading. Marking it <nav> spends a landmark on prose.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"file": "icon-buttons.md",
|
|
76
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Icon buttons\nA single icon as the whole control, in four styles and five sizes.\n\nComponent ID: `icon-buttons`\n\n[Component documentation](https://www.expressivecss.com/icon-buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/icon-buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
76
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Icon buttons\nA single icon as the whole control, in four styles and five sizes.\n\nComponent ID: `icon-buttons`\n\n[Component documentation](https://www.expressivecss.com/icon-buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/icon-buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/icon-buttons/overview)\n\nExample: A novel approval workflow should use a labeled button. A tooltip on an ambiguous icon cannot replace a clear label or the control's accessible name.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Google deprecates baseline filled, tonal and outlined token sets in favor of updated tokens, not those current icon-button variants. Do not rename framework tokens from Android examples.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/icon-buttons/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/icon-buttons/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/icon-buttons/guidelines).\n\nSupport (2026-09-13, `llm.md#icon-buttons`): Standard, filled, tonal, outlined; five sizes; narrow, wide, and square.\n\nWeb adaptation: Accessible name belongs to the control; the glyph is decorative.\n\nKnown boundary: Elevated and text are not icon-button variants.\n\nKnown boundary: Existing group checks cover selected icon colors and press shapes, not all standalone target sizes and disabled states.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#icon-buttons).\n\n#### Contract\n\nOne action as one icon. Add `icon-button` to a `<button>`, or to an `<a>` when it navigates, and put a single `<span class=\"material-symbols\" aria-hidden=\"true\">` inside. The icon is hidden, so `aria-label` is the only name the control has — an icon button without one fails the semantics suite.\n\nIt is a component, not a modifier on the common button: M3 gives it its own token families (`md.comp.icon-button.{xsmall…xlarge}` and `md.comp.icon-button-{standard,filled,tonal,outlined}`), so `.icon-button` takes none of the common-button geometry. Do not write `class=\"button icon-button\"`.\n\n#### Syntax\n\n```html\n<button type=\"button\" class=\"icon-button\" aria-label=\"Add\">\n <span class=\"material-symbols\" aria-hidden=\"true\">add</span>\n</button>\n\n<a class=\"icon-button\" href=\"/inbox\" aria-label=\"Inbox\">\n <span class=\"material-symbols\" aria-hidden=\"true\">inbox</span>\n</a>\n```\n\n#### Also documented\n\nThe Icon buttons section of the [API reference](https://www.expressivecss.com/llm.md) also covers Styles, Sizes, width and shape, Disabled and tokens.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `icon-button-is-a-control`: An icon button is a control: <button>, or <a href> when it navigates. A <div>, or an anchor with no href, is neither focusable nor announced.\n- `icon-button-link-is-not-fake-disabled`: A link cannot be disabled by a class. `pointer-events: none` stops the pointer and nothing else, so this stays in the tab order and still navigates on Enter - it looks inert and is not. Drop the href, or the link.\n- `icon-button-icon-hidden`: The ligature is real text and is read out verbatim. The icon in an icon button is decoration - the control carries the name - so it is aria-hidden=\"true\".\n- `icon-button-is-named`: The icon is hidden from assistive technology, so an icon button has nothing left to be named by. Give it an aria-label.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
"file": "lightbox.md",
|
|
80
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Lightbox\nLightbox for enlarge-on-click images.\n\nComponent ID: `lightbox`\n\n[Component documentation](https://www.expressivecss.com/media.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/media.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
80
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Lightbox\nLightbox for enlarge-on-click images.\n\nComponent ID: `lightbox`\n\n[Component documentation](https://www.expressivecss.com/media.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/media.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. No dedicated entry in the reviewed Google component inventory.\n\nExample: A payment confirmation needs a dialog, even if its design contains an image. Lightbox is for inspecting enlarged media.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: none. Web extension; no dedicated entry was observed in the reviewed current M3 component inventory.\n\nUpstream: web-extension-inventory-reviewed (2026-09-13); [evidence](https://m3.material.io/components).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-13, `llm.md#lightbox`): Enlarge-on-activation image and dismissal.\n\nWeb adaptation: ExpressiveCSS media behavior, not an upstream component contract.\n\nKnown boundary: Enlargement and teardown are checked; modal containment, reduced motion and destruction during closing remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#lightbox).\n\n#### Contract\n\nLightbox supports Space and native button activation. Repeated open or close requests are ignored; reopening during closing cancels the old transition. Canceled transitions do not report completion. Reduced motion skips animation and finishes pending transitions when enabled while mounted. Destroy cancels pending work, retains the original image, restores owned attributes and styles, and preserves trigger focus without overriding application focus. Shared ancestor overflow remains visible until the last open Lightbox releases it. This does not supply a modal-gallery focus contract.\n\nLightbox is Expressive’s material-style enlarge-on-click image. Click an image with `lightboxed` and it centers and grows. Click it again, scroll, or press Escape to dismiss. `AutoInit()` starts every `.lightboxed` image except those marked `no-autoinit`.\n\n#### Syntax\n\n```html\n<img class=\"lightboxed\" tabindex=\"0\" role=\"button\" width=\"650\" alt=\"A mountain lake\" src=\"images/sample-1.jpg\">\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `inDuration` | Number | `275` | Open transition duration, in milliseconds. |\n| `outDuration` | Number | `200` | Close transition duration, in milliseconds. |\n| `onOpenStart` | Function | `null` | Called before the lightbox opens. |\n| `onOpenEnd` | Function | `null` | Called after the lightbox opens. |\n| `onCloseStart` | Function | `null` | Called before the lightbox closes. |\n| `onCloseEnd` | Function | `null` | Called after the lightbox closes. |\n\n#### Methods\n\n- `.open()`: Open the lightbox.\n- `.close()`: Close the lightbox.\n- `.destroy()`: Destroy the plugin instance and tear down its event handlers.\n\n#### Also documented\n\nThe Lightbox section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Properties, Captions.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `lightbox-trigger-is-operable`: A .lightboxed image opens an overlay on click, which makes it a control - and a bare <img> is not focusable and not operable from the keyboard. Wrap it in a <button>, or give it tabindex=\"0\" and a role.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"file": "lists.md",
|
|
84
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Lists\nContinuous vertical indexes of text and images.\n\nComponent ID: `lists`\n\n[Component documentation](https://www.expressivecss.com/lists.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/lists.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
84
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Lists\nContinuous vertical indexes of text and images.\n\nComponent ID: `lists`\n\n[Component documentation](https://www.expressivecss.com/lists.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/lists.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/lists/overview)\n\nExample: A product with a large image, description, price, and several actions may need a card. A simple product-name index remains a list.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/lists/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/lists/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/lists/guidelines).\n\nSupport (2026-09-13, `llm.md#lists`): Standard and segmented lists.\n\nWeb adaptation: Native list semantics; visual selection alone does not justify aria-selected.\n\nKnown boundary: Ordinary native lists and child controls do not implement Google composite arrow navigation.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#lists).\n\n#### Contract\n\nContinuous, vertical indexes of text and images. Use a list so people can find an item and act on it. There is no JavaScript — the HTML is the component.\n\nThe leading visual is the first icon, `<img>`, or `<input>`. The trailing action is the last icon, `<kbd>`, `<button>`, `<time>`, or `.meta`. A following `<p>` is supporting text. Mark the current row with `active` or `selected` — **not** `aria-selected`, which is not valid on a plain `listitem` and needs a role (`option`, `tab`, `row`, `treeitem`) that brings a keyboard contract with it.\n\nTwo variants: standard (the default) and `segmented`.\n\n#### Syntax\n\n```html\n<ul class=\"list\">\n <li>\n <span class=\"material-symbols\" aria-hidden=\"true\">star</span>\n List item\n <kbd>⌘C</kbd>\n </li>\n <li class=\"selected\">\n <span class=\"material-symbols\" aria-hidden=\"true\">star</span>\n List item\n <kbd>⌘C</kbd>\n </li>\n</ul>\n```\n\n#### Also documented\n\nThe Lists section of the [API reference](https://www.expressivecss.com/llm.md) also covers Standard, Segmented, Text, Icons, Links.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `list-item-not-selected`: aria-selected is not valid on a listitem. A plain <ul> has nowhere to put it - either give the item a role that takes it (option, tab, row, treeitem) and implement that role’s keyboard contract, or drop the attribute.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
"file": "loading-indicator.md",
|
|
88
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Loading indicator\nA shape that morphs while it spins, for waits under five seconds.\n\nComponent ID: `loading-indicator`\n\n[Component documentation](https://www.expressivecss.com/loading-indicator.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/loading-indicator.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
88
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Loading indicator\nA shape that morphs while it spins, for waits under five seconds.\n\nComponent ID: `loading-indicator`\n\n[Component documentation](https://www.expressivecss.com/loading-indicator.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/loading-indicator.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/loading-indicator/overview)\n\nExample: A file upload reporting 42% needs determinate progress, not the morphing loading shape. A longer unmeasured job needs indeterminate progress. Do not flash an indicator for an effectively instant response or announce a fabricated value.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Use for brief unknown waits, typically under five seconds. Do not replace progress that transitions from unknown to determinate, or circular progress within buttons.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/loading-indicator/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/loading-indicator/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/loading-indicator/guidelines).\n\nSupport (2026-09-13, `llm.md#loading-indicator`): Uncontained and contained morphing loading indicator.\n\nWeb adaptation: CSS-only; the author supplies an accessible waiting message.\n\nKnown boundary: The framework requires a named status while Google recommends progressbar; an indeterminate progressbar validly omits aria-valuenow.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#loading-indicator).\n\n#### Contract\n\nM3 Expressive's indicator for a short wait — a shape that morphs while it spins.\n\nReach for it whenever the wait is under about five seconds and you cannot report a percentage. It replaces most short indeterminate circular uses. Keep a progress indicator for a process that will transition to a determinate value; Google's button guidance also retains circular progress. `.progress` supports both linear bars and determinate cases.\n\nOne element, CSS-only, no JavaScript plugin. The element is empty, so it reports nothing on its own. Supply a named waiting state and meaningful status text updates; verify spoken delivery with assistive technology. An indeterminate `progressbar` is also valid and omits `aria-valuenow`. The current framework contract requires a named status. A name alone does not prove an announcement.\n\n#### Syntax\n\n```html\n<span class=\"loading-indicator\" role=\"status\" aria-label=\"Loading\"></span>\n```\n\n#### Also documented\n\nThe Loading indicator section of the [API reference](https://www.expressivecss.com/llm.md) also covers Contained, Tokens.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `loading-indicator-reports-itself`: The current loading-indicator contract requires role=\"status\". Provide meaningful waiting text updates and verify announcement delivery; a role alone does not prove spoken output.\n- `loading-indicator-is-named`: Name the waiting state with aria-label or aria-labelledby. Verify meaningful status updates separately from its accessible name.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"file": "menu.md",
|
|
92
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Menu\nMaterial Design 3 menus, from the HTML.\n\nComponent ID: `menu`\n\n[Component documentation](https://www.expressivecss.com/menu.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/menu.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
92
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Menu\nMaterial Design 3 menus, from the HTML.\n\nComponent ID: `menu`\n\n[Component documentation](https://www.expressivecss.com/menu.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/menu.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/menus/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/menus/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/menus/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/menus/guidelines).\n\nSupport (2026-09-13, `llm.md#menu`): Vertical menus, nested flyouts, grouping, and standard/vibrant styles.\n\nWeb adaptation: Native menu/li structure; Menu owns opening and keyboard behavior.\n\nKnown boundary: Closing focus exclusion, scoped nested keys, RTL flyout placement and representative item targets have browser checks. Spoken output and full visual parity remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#menu).\n\n#### Contract\n\nMaterial Design 3 menus, from the HTML.\n\nClosing menus are excluded from keyboard focus, and close callbacks preserve focus they move. Submenu entry/return keys mirror in RTL; typeahead stays in the active list and skips headings and disabled items. Escape closes the innermost submenu first. Fine-pointer hover opens flyouts; keyboard activation uses Enter, Space, or the submenu entry arrow.\n\nInside open or closed shadow roots, `closeOnClick` controls item clicks just as it does in the document. Submenu triggers keep the parent menu open; outside clicks dismiss it.\n\n#### Syntax\n\n```html\n<button class=\"menu-trigger\" data-target=\"menu1\">Drop me</button>\n<menu id=\"menu1\">\n <li><button type=\"button\">One</button></li>\n <li><button type=\"button\">Two</button></li>\n <li class=\"divider\" role=\"separator\"></li>\n <li><button type=\"button\">Three</button></li>\n <li>\n <button type=\"button\">\n <span class=\"material-symbols\" aria-hidden=\"true\">cloud</span>\n <span>Five</span>\n </button>\n </li>\n</menu>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `alignment` | String | `'left'` | Edge the menu is aligned to. `'left'` or `'right'`. |\n| `autoFocus` | Boolean | `true` | If true, automatically focus the menu for keyboard navigation. This option is named `autoFocus`, not `autoTrigger`. |\n| `constrainWidth` | Boolean | `true` | If true, the menu is as wide as the trigger. M3 menus are independently sized — pass `false` for that. |\n| `container` | Element | `null` | Element that will contain the menu. When omitted, the menu is moved next to the trigger. |\n| `coverTrigger` | Boolean | `false` | If false, the menu opens below the trigger (the M3 placement). Pass `true` to cover the trigger. |\n| `closeOnClick` | Boolean | `true` | If true, close the menu when an item is clicked. |\n| `hover` | Boolean | `false` | If true, the menu opens on hover instead of click. |\n| `inDuration` | Number | `150` | Enter transition duration, in milliseconds. |\n| `outDuration` | Number | `250` | Exit transition duration, in milliseconds. |\n| `onOpenStart` | Function | `null` | Called when the menu starts opening. |\n| `onOpenEnd` | Function | `null` | Called when opening completes; superseded transitions and destruction cancel it. |\n| `onCloseStart` | Function | `null` | Called when the menu starts closing. |\n| `onCloseEnd` | Function | `null` | Called when closing completes; reopening and destruction cancel it. |\n| `onItemClick` | Function | `null` | Called when an item is clicked. Receives the `li`. |\n\n#### Methods\n\n- `.open()`: Open the menu.\n- `.close()`: Close the menu. With `autoFocus`, focus returns to the trigger when it remains in the menu. Focus moved to an outside control is preserved.\n- `.recalculateDimensions()`: While the menu is open, recalculate its dimensions if its contents have changed.\n- `.destroy()`: Destroy the plugin instance and tear down its event handlers.\n\n#### Also documented\n\nThe Menu section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `menu-children-are-list-items`: <menu> is a list: its content model permits only <li>. A bare <hr> between entries is invalid - put the separator inside an <li>, or use role=separator there.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
"file": "navigation-bar.md",
|
|
96
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Navigation bar\nSwitch between UI views on compact and medium screens.\n\nComponent ID: `navigation-bar`\n\n[Component documentation](https://www.expressivecss.com/navigation-bar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navigation-bar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
96
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Navigation bar\nSwitch between UI views on compact and medium screens.\n\nComponent ID: `navigation-bar`\n\n[Component documentation](https://www.expressivecss.com/navigation-bar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navigation-bar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/navigation-bar/overview)\n\nExample: Overview/Activity within an account page should not displace Home/Search/Profile in app navigation. Use tabs for those local panels and preserve the app destinations across widths.\n\n- expanded window: replace-with [navigation-rail](./navigation-rail.md). Use persistent peer navigation at wider widths.\n\n#### Material mapping\n\nRelationship: component. Google replaces the baseline bar with the flexible bar. The documented stacked/horizontal navigation-bar layouts remain current; do not exclude the family by its name.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/navigation-bar/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\nSupport (2026-09-07, `llm.md#navigation-bar`): Stacked and horizontal destination layouts.\n\nWeb adaptation: Links navigate; the application marks the current destination.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#navigation-bar).\n\n#### Contract\n\nSwitch between UI views on compact and medium screens. A `nav.navigation-bar` holds 3–5 destinations of equal importance. Destinations do not change from screen to screen. There is no JavaScript — mark the current view with `aria-current=\"page\"` (or `active`).\n\nThis is not the app bar. The app bar names the current page and holds 1–2 actions. Use a navigation bar in compact windows, a bar or rail in medium windows, and an expanded navigation rail in wider windows.\n\nDefault. Icon above the label. The selected destination puts a pill behind the icon and fills the glyph.\n\n#### Syntax\n\n```html\n<nav class=\"navigation-bar\" aria-label=\"Main\">\n <a href=\"/\" aria-current=\"page\">\n <span class=\"material-symbols\" aria-hidden=\"true\">home</span>\n Home\n </a>\n <a href=\"/browse\">\n <span class=\"material-symbols\" aria-hidden=\"true\">explore</span>\n Browse\n </a>\n <a href=\"/radio\">\n <span class=\"material-symbols\" aria-hidden=\"true\">radio</span>\n Radio\n </a>\n <a href=\"/library\">\n <span class=\"material-symbols\" aria-hidden=\"true\">library_music</span>\n Library\n </a>\n</nav>\n```\n\n#### Also documented\n\nThe Navigation bar section of the [API reference](https://www.expressivecss.com/llm.md) also covers Stacked, Horizontal, Fixed.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `navigation-bar-marks-current`: The active destination needs aria-current=\"page\".\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"file": "navigation-rail.md",
|
|
100
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Navigation rail\nSwitch between UI views on mid-sized devices.\n\nComponent ID: `navigation-rail`\n\n[Component documentation](https://www.expressivecss.com/navigation-rail.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navigation-rail.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
100
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Navigation rail\nSwitch between UI views on mid-sized devices.\n\nComponent ID: `navigation-rail`\n\n[Component documentation](https://www.expressivecss.com/navigation-rail.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/navigation-rail.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/navigation-rail/overview)\n\n- compact window: replace-with [navigation-bar](./navigation-bar.md). Compact peer destinations fit the bottom edge.\n- expanded window: variant. Use the expanded rail when labels should remain visible.\n\n#### Material mapping\n\nRelationship: component. Google replaces the baseline rail with the collapsed rail and the drawer with the expanded rail. The documented collapsed, expanded and modal variants remain current. Retain a drawer only for compatibility, an explicit request or a verified target-version nesting gap.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/navigation-rail/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/navigation-rail/specs); full specs unreviewed.\n\nSupport (2026-09-07, `llm.md#navigation-rail`): Collapsed, expanded, and modal rails.\n\nWeb adaptation: The compact expanded rail uses a scrim and dismissal behavior.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#navigation-rail).\n\n#### Contract\n\nSwitch between UI views on mid-sized devices. A `nav.navigation-rail` holds 3–7 destinations plus an optional FAB. Put it in the same place on every screen.\n\nCollapsed is 96dp with the icon above the label. Add `expanded` for 220–360dp, icon and label on one row, and an extended FAB. The menu button toggles that class (`AutoInit()` starts it). On compact windows an expanded rail is modal — a scrim, and Escape or a scrim tap collapses it. Add `modal` to keep that overlay at every breakpoint.\n\nEscape closes an open nested menu first. A second Escape collapses the modal rail and returns focus from inside it to the rail toggle, unless a close callback moves focus elsewhere.\n\n#### Syntax\n\n```html\n<nav class=\"navigation-rail\" aria-label=\"Main\">\n <button type=\"button\" aria-label=\"Menu\">\n <span class=\"material-symbols\" aria-hidden=\"true\">menu</span>\n </button>\n <a class=\"button extra\" href=\"/compose\">\n <span class=\"material-symbols\" aria-hidden=\"true\">edit</span>\n <span>Compose</span>\n </a>\n <a href=\"/\" aria-current=\"page\">\n <span class=\"material-symbols\" aria-hidden=\"true\">star</span>\n Label\n </a>\n <a href=\"/two\" aria-label=\"Starred, 3 unread\">\n <span class=\"material-symbols\" aria-hidden=\"true\">star<span class=\"badge\">3</span></span>\n Label\n </a>\n</nav>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `navigation-rail-marks-current`: The active destination needs aria-current=\"page\".\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"file": "pagination.md",
|
|
104
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Pagination\nA list of pages. The HTML is the component.\n\nComponent ID: `pagination`\n\n[Component documentation](https://www.expressivecss.com/pagination.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/pagination.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
104
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Pagination\nA list of pages. The HTML is the component.\n\nComponent ID: `pagination`\n\n[Component documentation](https://www.expressivecss.com/pagination.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/pagination.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. No dedicated entry in the reviewed Google component inventory.\n\nExample: A long article with Introduction/Methods/Results needs section links, optionally with scrollspy, not numbered result pages.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: none. Web extension; no dedicated entry was observed in the reviewed current M3 component inventory.\n\nUpstream: web-extension-inventory-reviewed (2026-09-13); [evidence](https://m3.material.io/components).\n\nRequirements and boundaries: design reference web-extensions-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-13, `llm.md#pagination`): Page links, active page, and unavailable previous/next items.\n\nWeb adaptation: CSS-only navigation; the application supplies destinations.\n\nKnown boundary: aria-disabled and pointer-events alone cannot disable a link for keyboard users.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#pagination).\n\n#### Contract\n\nSplit long content into shorter, easier blocks.\n\nAdd pagination links to split long content into shorter blocks. The component is CSS-only: a `pagination` list of links. There is no JavaScript plugin.\n\nThe list lives in a `<nav aria-label=\"Pagination\">` — a page's links are navigation, and the label distinguishes it from every other `<nav>` on the page.\n\n#### Syntax\n\n```html\n<nav class=\"pagination\" aria-label=\"Pagination\">\n <ol>\n <li class=\"disabled\">\n <span aria-hidden=\"true\"><span class=\"material-symbols\" aria-hidden=\"true\">chevron_left</span></span>\n </li>\n <li class=\"active\"><a href=\"?page=1\" aria-current=\"page\">1</a></li>\n <li><a href=\"?page=2\">2</a></li>\n <li><a href=\"?page=3\">3</a></li>\n <li><a href=\"?page=4\">4</a></li>\n <li><a href=\"?page=5\">5</a></li>\n <li>\n <a href=\"?page=2\" aria-label=\"Next page\"><span class=\"material-symbols\" aria-hidden=\"true\">chevron_right</span></a>\n </li>\n </ol>\n</nav>\n```\n\n#### Also documented\n\nThe Pagination section of the [API reference](https://www.expressivecss.com/llm.md) also covers Responsive.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `pagination-in-nav`: Pagination is navigation and belongs in a labelled <nav>, or it is just a list of numbers.\n- `pagination-marks-current`: The current page needs aria-current=\"page\". A class only colours it.\n- `pagination-disabled-not-a-link`: A disabled control that is still an <a href> stays in the tab order and still navigates. Use a <span>, or drop the href.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
"file": "panes.md",
|
|
108
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Panes\nMaterial 3 canonical layouts, from the HTML.\n\nComponent ID: `panes`\n\n[Component documentation](https://www.expressivecss.com/panes.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/panes.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
108
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Panes\nMaterial 3 canonical layouts, from the HTML.\n\nComponent ID: `panes`\n\n[Component documentation](https://www.expressivecss.com/panes.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/panes.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/foundations/layout/canonical-examples/overview)\n\nExample: A contact directory with no detail view needs a list. Use list-detail panes when selecting a contact reveals a separate detail region.\n\n- medium container: variant. Stack or collapse panes when their container cannot preserve useful pane widths.\n\n#### Material mapping\n\nRelationship: pattern. Canonical layout pattern, not a standalone component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/foundations/layout/canonical-examples/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-17, `llm.md#panes`): List-detail, supporting pane, and equal panes.\n\nWeb adaptation: CSS viewport and container queries; the application chooses the active compact pane.\n\nKnown boundary: Compact supporting layouts retain one-active-pane selection rather than automatic stacking. Native zoom, assistive technology and physical-device review remain pending.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#panes).\n\n#### Contract\n\nMaterial 3 canonical layouts — list-detail, supporting pane, and equal panes.\n\nPanes are CSS-only. A container (`panes`, or one of the named aliases `list-detail`, `supporting-pane-layout`, `pane-layout`) holds two or three `pane` children. Layout decisions use the nearest ancestor with inline-size or size containment, falling back to viewport media rules when none exists. Set `container-type: inline-size` on the containing column for nested layouts. The pane layout cannot query its own size. Compact widths (`< 600px`) use 16px inline margins; wider layouts use 24px margins and spacers. Below 840px only one pane shows at a time; at 840px and up the panes sit side by side. Google recommends stacking supporting content below primary content on compact and medium layouts; the current one-active-pane behavior is a framework adaptation. Footer actions wrap to keep translated labels reachable.\n\nAny of `pane`, `list-pane`, `primary-pane`, `detail-pane`, and `supporting-pane` counts as a pane child — the specific names are for readability.\n\n#### Syntax\n\n```html\n<div class=\"panes list-detail\">\n <div class=\"list-pane\">\n <header>\n <h2>Inbox</h2>\n </header>\n <ul class=\"list\">\n <li><a href=\"/inbox/brunch\">Brunch this weekend?</a></li>\n <li><a href=\"/inbox/design-review\">Design review</a></li>\n </ul>\n </div>\n <div class=\"detail-pane\">\n <header>\n <button aria-label=\"Back\"><span class=\"material-symbols\" aria-hidden=\"true\">arrow_back</span></button>\n <h2>Brunch this weekend?</h2>\n </header>\n <section>\n <p>Detail content.</p>\n </section>\n </div>\n</div>\n```\n\n#### Also documented\n\nThe Panes section of the [API reference](https://www.expressivecss.com/llm.md) also covers List-detail, Compact, Supporting pane, Equal, Three-pane, Appearance, Pane anatomy, Tokens.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `pane-is-not-main`: A document has one <main>, and a pane is a region inside it, not another one. Use <section>.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
"file": "progress.md",
|
|
112
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Progress indicators\nActivity and progress. The HTML is the indicator.\n\nComponent ID: `progress`\n\n[Component documentation](https://www.expressivecss.com/preloader.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/preloader.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
112
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Progress indicators\nActivity and progress. The HTML is the indicator.\n\nComponent ID: `progress`\n\n[Component documentation](https://www.expressivecss.com/preloader.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/preloader.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/progress-indicators/overview)\n\nExample: A brief unknown refresh fits a loading indicator. An upload needs accurate determinate progress, even if short. Keep circular progress when an unknown process becomes determinate or runs inside a button; indeterminate linear bars remain supported. Never invent a percentage.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component. Google replaces most short indeterminate circular waits with a loading indicator. Keep circular progress in buttons and for processes that become determinate; keep determinate and indeterminate linear progress. Deprecated baseline token sets do not deprecate these families.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/progress-indicators/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/progress-indicators/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/progress-indicators/guidelines).\n\nSupport (2026-09-13, `llm.md#progress-indicators`): Linear and circular progress, determinate and indeterminate.\n\nWeb adaptation: Prefer native progress where applicable; supply accessible state for custom hosts.\n\nKnown boundary: Forced-colors rendering is checked in browser emulation; Windows high-contrast and spoken output still require manual review.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#progress).\n\n#### Contract\n\nNative and custom progress use system colors in forced-colors mode, outline empty linear tracks, and preserve circular value segments. Reduced motion retains static feedback, including the legacy preloader. Browser emulation checks do not replace Windows high-contrast or screen-reader review.\n\nActivity and progress indicators for content that takes time to load.\n\nIf content will take a while to load, give the user feedback. Expressive ships linear progress bars and circular spinners. Both are CSS-only — there is no JavaScript plugin.\n\n#### Syntax\n\n```html\n<progress class=\"progress\" value=\"70\" max=\"100\"></progress>\n\n<div class=\"progress\" role=\"progressbar\" aria-valuenow=\"70\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"determinate\" style=\"width: 70%\"></div>\n</div>\n\n<div class=\"progress\" role=\"progressbar\" aria-valuenow=\"70\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"--md-comp-progress-value: 70%\"></div>\n```\n\n#### Also documented\n\nThe Progress indicators section of the [API reference](https://www.expressivecss.com/llm.md) also covers Linear, Circular.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `div-progress-reports-progress`: <progress> reports itself. A <div class=\"progress\"> is a bar drawn with CSS and reports nothing - it needs role=\"progressbar\", plus aria-valuenow/min/max when it is determinate.\n- `determinate-progress-reports-its-value`: role=\"progressbar\" with no aria-valuenow is an *indeterminate* bar. A determinate one draws a width the user can see and must report the same number: aria-valuenow, plus valuemin/valuemax when they are not 0 and 100.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"file": "radio-buttons.md",
|
|
116
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Radio buttons\nMaterial Design 3 radios, from the HTML.\n\nComponent ID: `radio-buttons`\n\n[Component documentation](https://www.expressivecss.com/radio-buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/radio-buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
116
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Radio buttons\nMaterial Design 3 radios, from the HTML.\n\nComponent ID: `radio-buttons`\n\n[Component documentation](https://www.expressivecss.com/radio-buttons.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/radio-buttons.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/radio-button/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/radio-button/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/radio-button/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/radio-button/guidelines).\n\nSupport (2026-09-13, `llm.md#radio-buttons`): Native radio groups and disabled controls.\n\nWeb adaptation: Shared name provides exclusivity; fieldset/legend names the group.\n\nKnown boundary: Native group selection is checked; initially-empty and disabled-option paths remain unmeasured.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#radio-buttons).\n\n#### Contract\n\nMaterial Design 3 radios, from the HTML.\n\nA `<label>` wrapping `<input type=\"radio\">` is the control. The label text is a sibling of the input — no extra class, no required `<span>`. They are CSS only. There is no JavaScript component and nothing to AutoInit.\n\nA radio only means anything as one of a set, so the set is a `<fieldset>` and the `<legend>` names the question the radios answer. Without it the options are announced one by one with nothing saying what is being chosen.\n\n#### Syntax\n\n```html\n<fieldset>\n <legend>Colour</legend>\n <label>\n <input name=\"group1\" type=\"radio\" checked>\n Red\n </label>\n <label>\n <input name=\"group1\" type=\"radio\">\n Yellow\n </label>\n <label>\n <input name=\"group1\" type=\"radio\" disabled>\n Brown\n </label>\n</fieldset>\n```\n\n#### Also documented\n\nThe Radio Buttons section of the [API reference](https://www.expressivecss.com/llm.md) also covers In a row.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `radio-in-fieldset`: A radio only means something as one of a group, and the group needs a <fieldset> with a <legend> to name the question being answered.\n- `radio-labelled`: A radio must be inside its <label> or carry an id a label points at.\n- `fieldset-has-legend`: A fieldset without a legend groups controls visually but names nothing.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"file": "scrollspy.md",
|
|
120
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Scrollspy\nHighlight the table of contents as the page scrolls.\n\nComponent ID: `scrollspy`\n\n[Component documentation](https://www.expressivecss.com/scrollspy.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/scrollspy.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
120
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Scrollspy\nHighlight the table of contents as the page scrolls.\n\nComponent ID: `scrollspy`\n\n[Component documentation](https://www.expressivecss.com/scrollspy.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/scrollspy.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. No dedicated entry in the reviewed Google component inventory.\n\nExample: A settings screen with mutually exclusive panels needs tabs. Scrollspy only tracks sections already present in the scrolling document.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: none. Web extension; no dedicated entry was observed in the reviewed current M3 component inventory.\n\nUpstream: web-extension-inventory-reviewed (2026-09-13); [evidence](https://m3.material.io/components).\n\nRequirements and boundaries: design reference web-extensions-review. Full visual parity and spoken output unverified.\n\nSupport (2026-09-17, `llm.md#scrollspy`): Section tracking with per-section offsets and independent tables of contents grouped by getActiveElement callback identity.\n\nWeb adaptation: Web document navigation helper.\n\nKnown boundary: Independent TOCs must reuse one getActiveElement function per group. Screen-reader announcements, native zoom and physical-device checks remain pending.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#scrollspy).\n\n#### Contract\n\nHighlight the table of contents as the page scrolls.\n\nScrollspy watches a set of sections and which one is currently in view. The table of contents on the right of every documentation page is the live demo: the matching link gets `active`, and clicking a link scrolls to that section.\n\nPut `scrollspy` and an `id` on each section. The table of contents is a set of destinations within the page, so it lives in a labelled `<nav>`; use `table-of-contents` on its list and point each link at `#that-id`. `AutoInit()` starts every `.scrollspy` except those marked `no-autoinit`.\n\n#### Syntax\n\n```html\n<div class=\"row\">\n <div class=\"s12 m9\">\n <div id=\"introduction\" class=\"section scrollspy\">\n <p>Content</p>\n </div>\n <div id=\"structure\" class=\"section scrollspy\">\n <p>Content</p>\n </div>\n <div id=\"initialization\" class=\"section scrollspy\">\n <p>Content</p>\n </div>\n </div>\n <div class=\"hide-on-compact-only m3\">\n <nav aria-label=\"On this page\">\n <ul class=\"section table-of-contents\">\n <li><a href=\"#introduction\">Introduction</a></li>\n <li><a href=\"#structure\">Structure</a></li>\n <li><a href=\"#initialization\">Initialization</a></li>\n </ul>\n </nav>\n </div>\n</div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `scrollOffset` | Number | `200` | Per-section observer top inset and `--md-comp-scrollspy-offset` for native anchor scroll margins. |\n| `activeClass` | String | `'active'` | Class applied to the active table-of-contents link. |\n| `getActiveElement` | Function | see below | Returns a CSS selector for the element that should receive `activeClass`, given the section’s id. |\n| `keepTopElementActive` | Boolean | `false` | If true, keep the last section above the viewport active when the scrollbar is outside all spy sections. If there is no such section, the first one stays active. |\n\n#### Methods\n\n- `.destroy()`: Disconnect the section's observer, restore its original offset style, and update the current link within its group. Repeated destruction is safe.\n\n#### Also documented\n\nThe Scrollspy section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `toc-in-nav`: A table of contents is a set of destinations within the page. It belongs in a labelled <nav>.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"file": "search.md",
|
|
124
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Search\nA search bar, and the view it expands into.\n\nComponent ID: `search`\n\n[Component documentation](https://www.expressivecss.com/search.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/search.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
124
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Search\nA search bar, and the view it expands into.\n\nComponent ID: `search`\n\n[Component documentation](https://www.expressivecss.com/search.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/search.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/search/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/search/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/search/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/search/guidelines).\n\nSupport (2026-09-13, `llm.md#search`): Search bar and expanded search view.\n\nWeb adaptation: Application toggles hidden for docked views or opens a native dialog for full-screen views; optional Autocomplete owns suggestions.\n\nKnown boundary: CSS does not supply search results announcements or modal focus ownership.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#search).\n\n#### Contract\n\nA search bar, and the view it expands into.\n\nA `<search>` with `search-bar` on it is the bar: a leading icon or icon button, an `<input type=\"search\">`, and whatever trailing actions the query needs. The element is the landmark, so there is no `role=\"search\"` to add. The input goes in bare — the bar is the container, so none of the text-field chrome (`.field`, the underline, the floating label) applies.\n\nSpacing follows what is at each end: a bare glyph sits 16dp from the edge, an icon button 4dp, because the button already insets its own glyph by 12dp. An `<img>` in the bar is the account avatar — 30dp and circular; put it inside the button when it is tappable, so the 48dp target comes from the button. `.searchbar`, the pre-1.0 name, reaches the same rules.\n\n#### Syntax\n\n```html\n<search class=\"search-bar\" aria-label=\"Search\">\n <span class=\"material-symbols\" aria-hidden=\"true\">search</span>\n <input type=\"search\" aria-label=\"Search recipes\" placeholder=\"Search recipes\">\n <button type=\"button\" class=\"icon-button\" aria-label=\"Filters\">\n <span class=\"material-symbols\" aria-hidden=\"true\">tune</span>\n </button>\n</search>\n```\n\n#### Also documented\n\nThe Search section of the [API reference](https://www.expressivecss.com/llm.md) also covers Docked view, Full-screen view, Suggestions, Tokens.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `search-view-not-a-composite-widget`: The search view takes no composite role. Its contents are links and buttons reached with Tab; the combobox and listbox belong to the Autocomplete on the bar's input.\n- `search-bar-holds-a-search-input`: The bar's control is a search input. `type=\"search\"` is what tells assistive technology, the UA and the on-screen keyboard what the field is for, and it is static semantics, so the author states it. The selector names `.search-bar` and deliberately not the `.searchbar` alias: pre-1.0 markup of that shape predates the requirement, and holding old markup to a rule it could not have known is how a promise of an additive rename gets broken.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"file": "select.md",
|
|
128
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Select\nChoose one option, or several, from a styled menu.\n\nComponent ID: `select`\n\n[Component documentation](https://www.expressivecss.com/select.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/select.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
128
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Select\nChoose one option, or several, from a styled menu.\n\nComponent ID: `select`\n\n[Component documentation](https://www.expressivecss.com/select.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/select.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Related Google guidance](https://m3.material.io/components/menus/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: related. Related guidance is not a dedicated component specification.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/menus/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/menus/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/menus/guidelines).\n\nSupport (2026-09-17, `llm.md#select`): Single/multiple selection, optgroups, and browser-default fallback.\n\nWeb adaptation: Native select enhanced by runtime; this is related to menu/text-field patterns.\n\nKnown boundary: Native zoom, screen-reader announcements, Windows contrast themes and physical-device form interaction remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#select).\n\n#### Contract\n\nChoose one option, or several, from a styled menu.\n\nFilled enhanced selects reserve a label row that grows with wrapping and enlarged text. Leading icons retain their label spacing; supporting text stays outside the filled surface. Native and outlined variants retain their existing layouts.\n\nSelect turns a native `<select>` into a menu. Wrap it in a `.field` and give the label a matching `for`. `AutoInit()` starts every `select` except those marked `no-autoinit`. Add `browser-default` to keep the native control.\n\n#### Syntax\n\n```html\n<div class=\"field\">\n <select id=\"form-select-1\">\n <option value=\"\" disabled selected>Choose your option</option>\n <option value=\"1\">Option 1</option>\n <option value=\"2\">Option 2</option>\n <option value=\"3\">Option 3</option>\n </select>\n <label for=\"form-select-1\">Expressive Select</label>\n</div>\n\n<div class=\"field\">\n <select id=\"form-select-2\" multiple>\n <option value=\"\" disabled selected>Choose your option</option>\n <option value=\"1\">Option 1</option>\n <option value=\"2\">Option 2</option>\n <option value=\"3\">Option 3</option>\n </select>\n <label for=\"form-select-2\">Multiple Select</label>\n</div>\n\n<div class=\"field\">\n <select id=\"form-select-3\">\n <optgroup label=\"team 1\">\n <option value=\"1\">Option 1</option>\n <option value=\"2\">Option 2</option>\n </optgroup>\n <optgroup label=\"team 2\">\n <option value=\"3\">Option 3</option>\n <option value=\"4\">Option 4</option>\n </optgroup>\n </select>\n <label for=\"form-select-3\">Optgroups</label>\n</div>\n\n<div class=\"field\">\n <select id=\"form-select-4\">\n <option value=\"\" disabled selected>Choose your option</option>\n <option value=\"1\" data-icon=\"photo.jpg\">example 1</option>\n <option value=\"2\" data-icon=\"photo.jpg\" class=\"left\">example 2</option>\n </select>\n <label for=\"form-select-4\">Images in select</label>\n</div>\n\n<label for=\"form-select-6\">Browser Select</label>\n<select id=\"form-select-6\" class=\"browser-default\">\n <option value=\"\" disabled selected>Choose your option</option>\n <option value=\"1\">Option 1</option>\n</select>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `classes` | String | `''` | Space-separated classes added to the `.field` wrapper, either the parent `.field` or one the plugin creates. |\n| `menuOptions` | Object | `{}` | Options passed to `Menu`. See Menu. `coverTrigger` is forced to `false` and `closeOnClick` is forced to `false`. |\n\n#### Methods\n\n- `.getSelectedValues()`: Selected values as an array of strings.\n- `.refresh()`: Re-read native values, option labels, options and disabled states. The generated rows are rebuilt while the field and an existing Menu instance remain. Refresh preserves focus on a surviving option in an open menu; it does not emit a user `change` event. Call it after programmatic changes, including moving the select to another form or changing its `form` attribute, to rebind reset handling. There is no mutation observer.\n- `.destroy()`: Destroy the plugin instance, remove the menu, and restore the native select. Associated labels keep their original nodes and event listeners; teardown restores their attributes and authored positions.\n\n#### Also documented\n\nThe Select section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Properties, Disabled Styles.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `option-has-selected-state`: role=option promises a selection state. Without aria-selected the listbox never says which entry is chosen.\n- `field-container-class`: The field container is `.field`. `.input-field` matches nothing in the sheet - the only `.input-field` rule is `.chips.input-field`.\n- `field-icon-not-i`: <i> means idiomatic text, not icon. Use <span class=\"material-symbols\">.\n- `field-icon-hidden`: The ligature is read aloud. A field icon is decoration; the label names the control.\n- `field-icon-side`: A field icon must name its side with .prefix or .suffix. The positional fallback counts elements of the same *type*, which only ever worked for <i>.\n- `field-label-for`: A label that does not wrap its control has to name it. The floating label sits *after* the control and cannot wrap it, so it always needs `for`; a label that does wrap its control (the file input trigger) does not.\n- `field-control-id`: Without an id the label has nothing to point at.\n- `field-supporting-text-id`: Supporting and error text has to be referenceable to be announced with the control.\n- `field-supporting-text-linked`: A field with supporting text must point at it with aria-describedby, or the text is never read out with the control.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
"file": "side-sheet.md",
|
|
132
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Side sheet\nOptional content and actions, without interrupting the main view.\n\nComponent ID: `side-sheet`\n\n[Component documentation](https://www.expressivecss.com/side-sheet.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/side-sheet.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
132
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Side sheet\nOptional content and actions, without interrupting the main view.\n\nComponent ID: `side-sheet`\n\n[Component documentation](https://www.expressivecss.com/side-sheet.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/side-sheet.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `shared-runtime`. [Google guidance](https://m3.material.io/components/side-sheets/overview)\n\n- compact window: replace-with [bottom-sheet](./bottom-sheet.md). Secondary content must fit a compact window.\n- compact window: replace-with [dialogs](./dialogs.md). Use a dialog when a compact task must block progress.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/side-sheets/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/side-sheets/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/side-sheets/guidelines).\n\nSupport (2026-09-17, `llm.md#side-sheet`): Standard and modal side sheets.\n\nWeb adaptation: Native dialog and shared drag/dismiss behavior.\n\nKnown boundary: Rendered RTL docking, dragging and enlarged translated text are checked; native zoom, assistive technology and physical-device review remain pending.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#side-sheet).\n\n#### Contract\n\nA recent flick toward the docked edge dismisses the sheet. For short drags, pausing for at least 100ms or reversing direction lets it snap back.\n\nA `dialog.side-sheet` (or `.right` / `.left`) is optional content anchored to the side. `show()` is standard (1dp inner divider, no scrim). `showModal()` is modal (28dp inner corners, scrim). A `<header>` holds an optional back button, a `title-large` headline, and a close control. A last-child `form[method=dialog]` is the action row. Drag the header or the inner 24dp edge toward the docked side to dismiss.\n\nDocking is logical: `.start`, `.left` and `.left-sheet` use the start edge; the default, `.right` and `.right-sheet` use the end edge. Drag direction, inner-edge hit testing, modal corners and opening motion follow computed RTL direction. Headings and actions wrap; the body scrolls independently. Shared sheet dragging ignores secondary-pointer cancellation and resets when a sheet closes, is removed, or a primary press starts elsewhere. Dismissal thresholds are unchanged. Keep an explicit close control; native zoom, assistive technology and physical-device review remain pending.\n\n#### Syntax\n\n```html\n<dialog class=\"side-sheet\" aria-labelledby=\"headline-title\">\n <header>\n <h2 id=\"headline-title\">Headline</h2>\n <form method=\"dialog\">\n <button type=\"submit\" aria-label=\"Close\">\n <span class=\"material-symbols\" aria-hidden=\"true\">close</span>\n </button>\n </form>\n </header>\n <div>…</div>\n</dialog>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `dialog-is-named`: A <dialog> takes no name from its heading. Point aria-labelledby at that heading, or give it an aria-label - otherwise it opens announced as just \"dialog\".\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"file": "slider.md",
|
|
136
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Slider\nSelections from a range of values.\n\nComponent ID: `slider`\n\n[Component documentation](https://www.expressivecss.com/slider.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/slider.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
136
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Slider\nSelections from a range of values.\n\nComponent ID: `slider`\n\n[Component documentation](https://www.expressivecss.com/slider.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/slider.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `shared-runtime`. [Google guidance](https://m3.material.io/components/sliders/overview)\n\nExample: An invoice amount needs a labeled number field with appropriate precision. A slider fits approximate volume or brightness adjustment.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/sliders/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/sliders/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/sliders/guidelines).\n\nSupport (2026-09-17, `llm.md#sliders`): Standard, centered, range, horizontal/vertical, and five sizes.\n\nWeb adaptation: Native range inputs with runtime value-label and range coordination.\n\nKnown boundary: Native-handle alignment, paired interaction and emulated forced colors have browser coverage. Screen readers, physical touch devices and actual Windows contrast themes remain pending.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#slider).\n\n#### Contract\n\nSliders handle a maximum of zero and update value-label placement when the input resizes, including horizontal RTL placement.\n\nMaterial Design 3 sliders, from the HTML.\n\nAn `<input type=\"range\">` is the control. A wrapping `.slider` (or a `<label>`) is the host for the value label; `.range` and `.range-field` are the older names and still work.\n\n#### Syntax\n\n```html\n<label>\n Volume\n <input type=\"range\" min=\"0\" max=\"100\" value=\"40\">\n</label>\n```\n\n#### Methods\n\n- `.destroy()`: Destroy the plugin instance, remove the value label, tear down its event handlers, and restore the inline custom properties it changed.\n\n#### Also documented\n\nThe Sliders section of the [API reference](https://www.expressivecss.com/llm.md) also covers Variants, Sizes, Inset icon, stops, value, Vertical, Disabled, Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `range-labelled`: A range announces only its value unless something names it.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"file": "snackbar.md",
|
|
140
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Snackbar\nMaterial Design 3 snackbars, from the HTML.\n\nComponent ID: `snackbar`\n\n[Component documentation](https://www.expressivecss.com/snackbar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/snackbar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
140
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Snackbar\nMaterial Design 3 snackbars, from the HTML.\n\nComponent ID: `snackbar`\n\n[Component documentation](https://www.expressivecss.com/snackbar.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/snackbar.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `shared-runtime`. [Google guidance](https://m3.material.io/components/snackbar/overview)\n\nExample: A successful save can use a snackbar. Offline status that still allows editing needs a persistent inline message; a required irreversible-delete confirmation needs a dialog before the action.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/snackbar/overview).\n\nRequirements and boundaries: design reference feedback-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/snackbar/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/snackbar/guidelines).\n\nSupport (2026-09-13, `llm.md#snackbar`): Timed text feedback or persistent actionable messages, with optional close control and focused Escape dismissal.\n\nWeb adaptation: Use the documented announcement and timeout behavior.\n\nKnown boundary: Custom template actions require explicit persistence and a close control. Application keyboard reach controls and spoken live-region delivery need verification.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#snackbar).\n\n#### Contract\n\nSnackbars with an action are persistent and dismissible by default. Escape dismisses a focused snackbar; closing restores focus only when it remains inside the bar. Explicit finite timers still pause during focus or hover.\n\nMaterial Design 3 snackbars, from the HTML.\n\nSnackbars show short updates about app processes at the bottom of the screen. They should not interrupt browsing. A `.snackbar` is the bar. A `<p>` is the supporting text. A trailing `<button>` is the optional action; a `.circle` button is the optional close.\n\n#### Syntax\n\n```js\nnew Expressive.Snackbar({ text: 'Photo saved to album' });\n\nnew Expressive.Snackbar({\n text: 'Item archived',\n action: 'Undo',\n onAction: function() { /* restore */ }\n});\n\nnew Expressive.Snackbar({\n text: \"Can't send photo. Retry in 5 seconds.\",\n action: 'Retry',\n dismissible: true\n});\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `text` | String | `''` | Plain-text supporting text, wrapped in a `<p>`. If set, it replaces any HTML from `snackbarId`. |\n| `action` | String | `''` | Optional action label. Rendered as a trailing text button. |\n| `onAction` | Function | `null` | Called when the action button is pressed. The snackbar still dismisses. |\n| `dismissible` | Boolean | `false`, or `true` with an action | Show a trailing close icon button. An explicit false is preserved. |\n| `snackbarId` | String | — | Id of a `<template>` (or another element) used as the snackbar body. Templates are cloned. Other elements are moved into the snackbar and restored on dismissal or replacement, so the same ID can be reused. |\n| `displayLength` | Number | `4000` | Default 4000ms without an action, or Infinity with an action. Explicit finite timers need equivalent persistent feedback in the application. |\n| `inDuration` | Number | `300` | Enter transition duration, in milliseconds. |\n| `outDuration` | Number | `375` | Exit transition duration, in milliseconds. |\n| `classes` | String | `''` | Space-separated classes added to the snackbar. `rounded` is a stadium. `top` moves the bar off the bottom. |\n| `completeCallback` | Function | `null` | Called when the snackbar is dismissed. |\n| `activationPercent` | Number | `0.8` | Fraction of the snackbar’s width a drag must travel to dismiss it. |\n| `root` | Element | `null` | Any element in the tree the snackbar should render into. Pass one when the page lives in a shadow root, so the container is appended there rather than to `document.body`. |\n\n#### Methods\n\n- `.dismiss()`: Dismiss this snackbar with its exit animation. Runs `completeCallback` when the animation finishes.\n- `Snackbar.dismissAll()`: Dismiss every snackbar that is currently showing.\n\n#### Also documented\n\nThe Snackbar section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Markup, Properties, Custom HTML, Callback, Styling, Dismiss a Snackbar Programmatically.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\nNo component-specific `semantics.json` rules apply to this guide.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"file": "split-button.md",
|
|
144
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Split button\nA lead action and a trailing half that opens a menu of related ones, in five sizes.\n\nComponent ID: `split-button`\n\n[Component documentation](https://www.expressivecss.com/split-button.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/split-button.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
144
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Split button\nA lead action and a trailing half that opens a menu of related ones, in five sizes.\n\nComponent ID: `split-button`\n\n[Component documentation](https://www.expressivecss.com/split-button.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/split-button.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/split-button)\n\nExample: PDF/CSV format selection for a later Export action belongs in a select or native inputs. A split button fits Export now plus alternate export commands.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/split-button/overview).\n\nRequirements and boundaries: design reference layout-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/split-button/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/split-button/guidelines).\n\nSupport (2026-09-18, `llm.md#split-button`): Leading action and trailing menu trigger with matching styles.\n\nWeb adaptation: Reuses Menu; no separate split-button runtime.\n\nKnown boundary: Separate 48dp effective targets, native zoom, spoken output and physical-device behavior remain unverified.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#split-button).\n\n#### Contract\n\nOne action the user will take most of the time, next to a menu of the ones they might take instead — Save and \"save as\", Reply and \"reply all\", Export and every other format. The root is a `<div class=\"split-button\">` holding two buttons: a leading one that does the work, and a trailing `.menu-trigger` that opens a `<menu>`. The pair sits 2dp apart, the outside is round, and the seam between them is square-ish.\n\nThe trailing half is an ordinary Menu trigger, so everything Menu does it does here — `Expressive.AutoInit()` starts it, `data-target` names the surface, and the menu's keyboard model, alignment and options are unchanged. This component adds no script of its own. The one thing Menu does differently is width: a trigger narrower than the surface's own 112dp minimum is not a constraint it can honour, and this trigger is a chevron in a 48dp box, so the menu is sized to its own content instead.\n\n#### Syntax\n\n```html\n<div class=\"split-button\">\n <button class=\"button\">Save</button>\n <button class=\"button menu-trigger\" data-target=\"save-menu\" aria-label=\"More save options\">\n <span class=\"material-symbols\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n <menu id=\"save-menu\">\n <li><button type=\"button\">Save a copy</button></li>\n <li><button type=\"button\">Save as template</button></li>\n </menu>\n</div>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `split-button-is-not-an-authored-composite-widget`: A split button takes no composite role; its two halves are reached with Tab, not arrow keys. The <menu> the trailing half opens is the composite widget here, and it carries its own role.\n- `split-button-halves-are-controls`: A split button is exactly two controls and the menu one of them opens: a <button>, or an <a class=\"button\" href> when it navigates. A wrapper element is refused too - the seam, the insets and the larger trailing icon are all written against direct children, so a nested <div> loses every one of them.\n- `split-button-half-is-not-an-icon-button`: An icon button is its own component: its height, insets, colours, icon sizing and transitions are all set on the element itself, so it reaches none of the split button's geometry and fights the seam it is handed. The trailing half is <button class=\"button menu-trigger\">, which the container sizes like the leading one.\n- `split-button-trigger-is-the-trailing-half`: The menu trigger is the *trailing* half, and only the <menu> may follow it. Order is the whole of the geometry here: the halves are told apart by role, not by position, so a trigger written first still takes the trailing side's round outer corners while flex puts it on the leading side - a split button with its seam and its round ends swapped.\n- `split-button-is-two-controls`: A split button is exactly two controls: one lead action and one menu trigger. A third gets the leading half's rules as well, so two buttons draw round start corners and a seam against each other. Several peer actions are a button group; several related ones belong in the menu.\n- `split-button-has-a-leading-action`: A split button is a lead action *and* a menu of related ones; without the lead it is a menu trigger wearing half a pill. The trailing half's shape is written for a seam, so the only control ends up squared off on the edge it should be joined along, with nothing to join to. One control that opens a menu is a menu trigger - drop the container. Not fragmentSafe: what it detects is an omission, and a fragment omits by nature.\n- `split-button-has-a-trailing-menu-trigger`: The trailing half is the whole point: it opens a menu of actions related to the leading one. Without `.menu-trigger` on it there is no menu, and the pair is a lone button with a chevron glued to it - write two buttons, or one. Not fragmentSafe: what it detects is an omission, and a fragment omits by nature.\n- `split-button-trigger-names-its-menu`: Menu finds its surface through `data-target` on the trigger, falling back to an `href` fragment. A `.menu-trigger` with neither initializes against no element: it gets aria-haspopup and aria-expanded it will never change, which is a promise of a menu that does not exist.\n- `split-button-trailing-icon-hidden`: The ligature is real text and is read out verbatim, so an unhidden chevron names the trailing half \"arrow_drop_down\". It is decoration - the control carries the name - so it is aria-hidden=\"true\", and `icon-only-control-is-named` then requires the aria-label.\n- `split-button-expanded-is-not-authored`: Expanded is dynamic state, so the framework owns it. Menu's constructor stamps aria-expanded on the trigger and every open() and close() rewrites it; authoring it states a value that is about to be overwritten - and the expanded shape is drawn from that attribute, so an authored \"true\" draws an open split button over a closed menu.\n- `menu-children-are-list-items`: <menu> is a list: its content model permits only <li>. A bare <hr> between entries is invalid - put the separator inside an <li>, or use role=separator there.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
"file": "switches.md",
|
|
148
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Switches\nMaterial Design 3 switches, from the HTML.\n\nComponent ID: `switches`\n\n[Component documentation](https://www.expressivecss.com/switches.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/switches.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
148
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Switches\nMaterial Design 3 switches, from the HTML.\n\nComponent ID: `switches`\n\n[Component documentation](https://www.expressivecss.com/switches.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/switches.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/switch/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/switch/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/switch/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/switch/guidelines).\n\nSupport (2026-09-13, `llm.md#switches`): Native checkbox switches and disabled controls.\n\nWeb adaptation: Input state owns selection and form value.\n\nKnown boundary: The styled native checkbox does not perform or announce a persisted setting change.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#switches).\n\n#### Contract\n\nMaterial Design 3 switches, from the HTML.\n\nA `<label class=\"switch\">` wrapping `<input type=\"checkbox\">` is the control. The label text is a sibling of the input — no `.lever` required. They are CSS only. There is no JavaScript component and nothing to AutoInit.\n\nTokens follow the [M3 switch spec](https://m3.material.io/components/switch/specs). The track is 52×32dp. Unselected is `surface-variant` with a 2dp `outline` and a 16dp handle. Selected is a `primary` track and a 24dp `on-primary` handle. The state layer is 40dp at 8% hover and 10% focus. The touch target is 48dp. The label is `body-large` / `on-surface`. Disabled is 38%.\n\n#### Syntax\n\n```html\n<label class=\"switch\">\n <input type=\"checkbox\">\n Wi-Fi\n</label>\n\n<label class=\"switch\">\n <input type=\"checkbox\" checked>\n Bluetooth\n</label>\n\n<label class=\"switch\">\n <input type=\"checkbox\" disabled>\n Airplane mode\n</label>\n```\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `switch-is-label`: A switch is a <label> wrapping its checkbox - that is what makes the text its accessible name.\n- `switch-decorative-text-hidden`: On/off captions inside the label are folded into the accessible name, which then reads \"Off On\". Hide them and let the label text name the switch.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
149
149
|
},
|
|
150
150
|
{
|
|
151
151
|
"file": "tabs.md",
|
|
152
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Tabs\nMaterial Design 3 tabs, from the HTML.\n\nComponent ID: `tabs`\n\n[Component documentation](https://www.expressivecss.com/tabs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/tabs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
152
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Tabs\nMaterial Design 3 tabs, from the HTML.\n\nComponent ID: `tabs`\n\n[Component documentation](https://www.expressivecss.com/tabs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/tabs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/tabs/overview)\n\nExample: Home/Search/Profile are app destinations, so use a navigation bar or rail. Overview/Activity panels within one account page can use tabs; Day/Week/Month as a form value can use native radio inputs.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/tabs/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/tabs/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/tabs/guidelines).\n\nSupport (2026-09-13, `llm.md#tabs`): Primary and secondary tabs; stacked and horizontal icon layouts.\n\nWeb adaptation: Links target panels; use the shipped runtime keyboard contract.\n\nKnown boundary: Native links use Tab and aria-current; runtime does not implement composite tab arrow keys.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#tabs).\n\n#### Contract\n\nMaterial Design 3 tabs, from the HTML.\n\nA `<nav class=\"tabs\" aria-label=\"Sections\">` of `<a href=\"#panel\">` is the bar. A `<span>` (or the link text) is the label; a leading `<span class=\"material-symbols\">` is the icon. Nest a `<span class=\"badge\">` in the icon for a count, and put that count in the tab's `aria-label` so a hidden icon does not swallow it. `.active` is the selected tab. There is no `li.tab` required — `ul.tabs > li.tab > a` stays as an alias. `AutoInit()` starts every `.tabs` except those marked `no-autoinit`.\n\nTokens follow the [M3 tabs spec](https://m3.material.io/components/tabs/specs). Primary tabs sit on `surface`, 48dp (64dp with a stacked icon). The label is `title-small` / `on-surface-variant`; selected is `primary`. The indicator is 3dp `primary` with 3dp top corners. The icon is 24dp. A 1dp `outline-variant` divider runs under the bar. Hover is 8%; focus is 10%. Disabled is 38%.\n\n#### Syntax\n\n```html\n<nav class=\"tabs\" aria-label=\"Travel\">\n <a href=\"#flight\">\n <span class=\"material-symbols\" aria-hidden=\"true\">flight</span>\n <span>Flight</span>\n </a>\n <a class=\"active\" aria-current=\"page\" href=\"#luggage\" aria-label=\"Luggage, 3 unread\">\n <span class=\"material-symbols\" aria-hidden=\"true\">luggage<span class=\"badge\">3</span></span>\n <span>Luggage</span>\n </a>\n <a href=\"#explore\">\n <span class=\"material-symbols\" aria-hidden=\"true\">explore</span>\n <span>Explore</span>\n </a>\n</nav>\n<div id=\"flight\">Flight</div>\n<div id=\"luggage\">Luggage</div>\n<div id=\"explore\">Explore</div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `duration` | Number | `300` | Indicator transition duration, in milliseconds. |\n| `onShow` | Function | `null` | Called when a new tab panel is shown. Receives the panel element. |\n| `swipeable` | Boolean | `false` | Enable swipeable tabs. Uses `responsiveThreshold`. Wraps the panels in a carousel. |\n| `responsiveThreshold` | Number | `Infinity` | Maximum viewport width, in pixels, at which swipeable mode starts. Wider viewports stay non-swipeable. |\n\n#### Methods\n\n- `.select()`: Show the panel that belongs to the tab with this id. Panel IDs are matched literally, including numeric IDs and IDs containing dots, colons or brackets, in normal and swipeable modes.\n- `.updateTabIndicator()`: Recalculate the indicator position. Useful if the bar was hidden or resized.\n- `.destroy()`: Destroy the plugin instance and tear down its event handlers.\n\n#### Also documented\n\nThe Tabs section of the [API reference](https://www.expressivecss.com/llm.md) also covers Secondary, Initialization, Properties, Preselecting a tab, Linking to an External Page, Swipeable Tabs, Fixed width, Inline icons.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `tabs-not-a-tablist`: A tab strip takes no ARIA role here; these are links to in-page sections.\n- `tabs-marks-current`: The active tab is the section you are on; aria-current says so where a class cannot.\n\n#### Guide checks\n\n- Label every <nav> landmark with aria-label or aria-labelledby.\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"file": "text-fields.md",
|
|
156
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Text fields\nMaterial Design 3 text fields, from the HTML.\n\nComponent ID: `text-fields`\n\n[Component documentation](https://www.expressivecss.com/text-inputs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/text-inputs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
156
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Text fields\nMaterial Design 3 text fields, from the HTML.\n\nComponent ID: `text-fields`\n\n[Component documentation](https://www.expressivecss.com/text-inputs.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/text-inputs.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/text-fields/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/text-fields/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/text-fields/specs); full specs unreviewed.\n\nSupport (2026-09-07, `llm.md#text-inputs`): Filled and outlined fields, supporting text, and error states.\n\nWeb adaptation: Native input/textarea with explicit label and description relationships.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#text-fields).\n\n#### Contract\n\nMaterial Design 3 text fields, from the HTML.\n\nA `.field` is the container. The `<label>` after the control is the floating label, so it must carry `for` — it sits after the control and cannot wrap it. An icon names its side with `prefix` or `suffix` and is `aria-hidden`, because the ligature is real text. `<small>` is supporting text: give it an `id` and point the control at it with `aria-describedby`, or it is never read out with the field. The default is the M3 filled field; add `outlined` (or `border`) for the outlined variant.\n\n`.input-field` is **not** the container and never was — the only rule matching it in the sheet is `.chips.input-field`.\n\n#### Syntax\n\n```html\n<div class=\"field\">\n <input id=\"first_name\" type=\"text\" placeholder=\" \" aria-describedby=\"first_name_help\">\n <label for=\"first_name\">First name</label>\n <small id=\"first_name_help\">Supporting text</small>\n</div>\n\n<div class=\"field outlined\">\n <input id=\"last_name\" type=\"text\" placeholder=\" \">\n <label for=\"last_name\">Last name</label>\n</div>\n\n<div class=\"field\">\n <span class=\"material-symbols prefix\" aria-hidden=\"true\">place</span>\n <span class=\"material-symbols suffix\" aria-hidden=\"true\">gps_fixed</span>\n <input id=\"loc\" type=\"text\" placeholder=\" \">\n <label for=\"loc\">Location</label>\n</div>\n```\n\n#### Also documented\n\nThe Text Inputs section of the [API reference](https://www.expressivecss.com/llm.md) also covers Input types, Inline, Textarea, File input, Character counter.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `field-container-class`: The field container is `.field`. `.input-field` matches nothing in the sheet - the only `.input-field` rule is `.chips.input-field`.\n- `field-icon-not-i`: <i> means idiomatic text, not icon. Use <span class=\"material-symbols\">.\n- `field-icon-hidden`: The ligature is read aloud. A field icon is decoration; the label names the control.\n- `field-icon-side`: A field icon must name its side with .prefix or .suffix. The positional fallback counts elements of the same *type*, which only ever worked for <i>.\n- `field-label-for`: A label that does not wrap its control has to name it. The floating label sits *after* the control and cannot wrap it, so it always needs `for`; a label that does wrap its control (the file input trigger) does not.\n- `field-control-id`: Without an id the label has nothing to point at.\n- `field-supporting-text-id`: Supporting and error text has to be referenceable to be announced with the control.\n- `field-supporting-text-linked`: A field with supporting text must point at it with aria-describedby, or the text is never read out with the control.\n- `file-input-not-nested`: A control inside a control is not valid HTML and gives two overlapping hit targets. Use a <label> styled as a button.\n- `file-path-readonly`: The path field only ever displays what the file input holds; leaving it writable offers an edit that is discarded.\n- `counter-is-announced`: The count changes as the user types, so it has to be a live region or the remaining characters are never announced.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"file": "time-picker.md",
|
|
160
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Time picker\nPick a time from a clock face, in 12-hour or 24-hour form.\n\nComponent ID: `time-picker`\n\n[Component documentation](https://www.expressivecss.com/timepicker.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/timepicker.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
160
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Time picker\nPick a time from a clock face, in 12-hour or 24-hour form.\n\nComponent ID: `time-picker`\n\n[Component documentation](https://www.expressivecss.com/timepicker.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/timepicker.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/time-pickers/overview)\n\nExample: An appointment time can use a labeled native time input when platform entry is enough. Do not choose this picker expecting a popup: its clock stays inline.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: requirements-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/time-pickers/overview).\n\nRequirements and boundaries: design reference inputs-material-review. Full visual parity and spoken output unverified.\n\n[Specification link](https://m3.material.io/components/time-pickers/specs); full specs unreviewed.\n\n[Google guidelines](https://m3.material.io/components/time-pickers/guidelines).\n\nSupport (2026-09-18, `llm.md#time-picker`): Inline clock and digital input; 12-hour and 24-hour formats.\n\nWeb adaptation: Default inline presentation with optional docked display plugin; no open()/close() methods or modal implementation.\n\nKnown boundary: Modal picker parity is not provided by the documented inline API.\n\nKnown boundary: Named digital inputs, AM/PM state and input-event synchronization have browser coverage. Modal and clock-dial keyboard behavior remain incomplete.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#time-picker).\n\n#### Contract\n\nPick a time from a clock face, in 12-hour or 24-hour form.\n\nAdd `time-picker` to a text input. `AutoInit()` starts every `.time-picker` except those marked `no-autoinit`.\n\nThe clock is inline, not a modal. It is appended to the input’s parent and stays visible. There is no `openByDefault` flag. `open()` and `close()` are not provided.\n\n#### Syntax\n\n```html\n<div class=\"field\">\n <input type=\"text\" class=\"time-picker\" id=\"lunchtime\">\n <label for=\"lunchtime\">Lunchtime</label>\n</div>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `duration` | Number | `350` | Transition between the hours and minutes views, in milliseconds. |\n| `container` | Element or String | `null` | Element or selector to render the clock into. When omitted, it is appended to the input’s parent. |\n| `showClearBtn` | Boolean | `false` | Show a Clear button in the footer. |\n| `autoSubmit` | Boolean | `true` | If true, choosing a minute writes the input. If false, Ok and Cancel buttons are added. |\n| `defaultTime` | String | `'now'` | Initial time. `'now'` or a `'HH:MM'` string (optionally with `AM`/`PM`). |\n| `fromNow` | Number | `0` | Millisecond offset added to `'now'`. |\n| `i18n` | Object | See below | Labels for Cancel, Clear, Ok, Hours, and Minutes. |\n| `twelveHour` | Boolean | `true` | If true, use a 12-hour clock with AM/PM. If false, use 24-hour hours on two rings. |\n| `vibrate` | Boolean | `true` | Vibrate the device when the clock hand changes value. |\n| `onSelect` | Function | `null` | Called when a time is chosen on the dial. Receives `(hour, minute)`. |\n| `onInputInteraction` | Function | `null` | Called when the input is clicked or confirmed with Enter. |\n| `onDone` | Function | `null` | Called once when Ok is activated by click, Enter or Space. The button is created when `autoSubmit` is false. |\n| `onCancel` | Function | `null` | Called once when Cancel is activated by click, Enter or Space. The button is created when `autoSubmit` is false. |\n| `displayPlugin` | String | `null` | Set to `'docked'` for a click-to-open popover. |\n| `displayPluginOptions` | Object | `null` | Options for the docked plugin: `margin`, `transition`, `duration`, `align`. |\n\n#### Methods\n\n- `.showView()`: Show the hours or minutes face.\n- `.done()`: Write the current hours and minutes to the input. Pass a truthy argument to clear the input instead.\n- `.clear()`: Clear the input. Same as `done(true)`.\n- `.destroy()`: Destroy the plugin instance, remove the clock, and tear down its event handlers. Pending automatic submission and clock updates are cancelled, so the destroyed instance cannot write to the input.\n- `.open(); / .close()`: These methods are not provided. The clock defaults to visible inline presentation; `displayPlugin: 'docked'` enables docking. No modal implementation is available.\n\n#### Also documented\n\nThe Time Picker section of the [API reference](https://www.expressivecss.com/llm.md) also covers Initialization, Display, Internationalization, 12-hour and 24-hour, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\nNo component-specific `semantics.json` rules apply to this guide.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"file": "toolbars.md",
|
|
164
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Toolbars\nFrequently used actions for the current page.\n\nComponent ID: `toolbars`\n\n[Component documentation](https://www.expressivecss.com/toolbars.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/toolbars.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
164
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Toolbars\nFrequently used actions for the current page.\n\nComponent ID: `toolbars`\n\n[Component documentation](https://www.expressivecss.com/toolbars.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/toolbars.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `css-only`. [Google guidance](https://m3.material.io/components/toolbars/overview)\n\nExample: Home/Search/Profile belong in navigation. A toolbar near a document can hold edit, share, and formatting actions.\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/toolbars/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/toolbars/specs); full specs unreviewed.\n\nSupport (2026-09-07, `llm.md#toolbars`): Floating/docked, standard/vibrant, vertical floating, and companion FAB.\n\nWeb adaptation: CSS-only commands; no automatic composite toolbar keyboard model.\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#toolbars).\n\n#### Contract\n\nMaterial Design 3 toolbars, from the HTML.\n\nA `<div class=\"toolbar\">` is the bar — not a `<nav>`, because a toolbar holds commands rather than destinations. Direct `<button>` or `<a>` children are the actions. A `<span class=\"material-symbols\">` is the icon; wrap a label in its own `<span>`. An action with an icon and no label needs an `aria-label`. `.active` marks the selected action. They are CSS only. There is no JavaScript component and nothing to AutoInit.\n\nTokens follow the [M3 toolbar spec](https://m3.material.io/components/toolbars/specs). Actions are 48dp targets with a 24dp icon, transparent at rest, `on-surface-variant`, 4dp apart.\n\n#### Syntax\n\n```html\n<div class=\"toolbar\">\n <button type=\"button\" class=\"circle\" aria-label=\"Undo\">\n <span class=\"material-symbols\" aria-hidden=\"true\">undo</span>\n </button>\n <button type=\"button\" class=\"circle active\" aria-label=\"Bold\">\n <span class=\"material-symbols\" aria-hidden=\"true\">format_bold</span>\n </button>\n <button type=\"button\" class=\"circle\" aria-label=\"Italic\">\n <span class=\"material-symbols\" aria-hidden=\"true\">format_italic</span>\n </button>\n</div>\n```\n\n#### Also documented\n\nThe Toolbars section of the [API reference](https://www.expressivecss.com/llm.md) also covers Variants, Docked, Pairing with a FAB, Fixed.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `toolbar-not-nav`: A toolbar holds commands (Bold, Italic), not navigation, so it is not a <nav> landmark.\n- `toolbar-not-a-composite-widget`: A toolbar takes no composite role; its buttons are reached with Tab, not arrow keys.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"file": "tooltips.md",
|
|
168
|
-
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Tooltips\nMaterial Design 3 tooltips, from the HTML.\n\nComponent ID: `tooltips`\n\n[Component documentation](https://www.expressivecss.com/tooltips.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/tooltips.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.
|
|
168
|
+
"content": "<!-- Generated by scripts/gen-expressivecss-skill.mjs. Do not edit. -->\n\n### Tooltips\nMaterial Design 3 tooltips, from the HTML.\n\nComponent ID: `tooltips`\n\n[Component documentation](https://www.expressivecss.com/tooltips.html.md) · [Repository source](https://github.com/BaezFJ/ExpressiveCSS/blob/master/docs/src/pages/tooltips.astro) · [Matching tag](https://github.com/BaezFJ/ExpressiveCSS/tree/v0.12.0)\n\nContract: ExpressiveCSS 0.12.0\n\nSources: `llm.md`, `semantics.json`, `docs/src/data/nav.ts`, `docs/src/data/component-decisions.json`, `package.json`, `CHANGELOG.md`\n\nContract SHA-256: `270b7d8fd0ec2f1174cba3f2793c061d3b4f494903520e2eaaa7fa640a680859`\n\n#### Selection and adaptation\n\nRuntime ownership: `auto-init`. [Google guidance](https://m3.material.io/components/tooltips/overview)\n\nUse the documented component at each reachable width; no catalogue substitution is prescribed.\n\n#### Material mapping\n\nRelationship: component.\n\nUpstream: overview-specs-guidelines-accessibility-prose-reviewed (2026-09-13); [evidence](https://m3.material.io/components/tooltips/overview).\n\nRendered prose reviewed; collapsed token tables, image-only measurements, runtime and full parity unverified. See the design priority component review for requirement-level findings.\n\n[Specification link](https://m3.material.io/components/tooltips/specs); full specs unreviewed.\n\nSupport (2026-09-07, `llm.md#tooltips`): Plain and rich tooltips; CSS child and runtime-generated forms.\n\nWeb adaptation: The selected form determines ownership; CSS-only hover/focus is not runtime initialization.\n\nKnown boundary: For hover/focus tooltips, verify dismissibility, hoverability, and persistence under WCAG SC 1.4.13, including its exceptions. Plain CSS bubbles disable pointer events and have no own Escape handler; aria-describedby alone does not verify these behaviors. Read the [focused web checks](../expressivecss-accessibility/references/web-checks.md#content-on-hover-or-focus).\n\nFull parity remains unassessed. [Capability evidence](../references/capability-roadmap.md#tooltips).\n\n#### Contract\n\nMaterial Design 3 tooltips, from the HTML.\n\nA child `.tooltip` is the bubble. No `tooltipped` class is required. They are CSS only on hover and keyboard focus. Helpers are only for placement and the rich variant: `top` (the default), `bottom`, `left`, `right`, `rich` / `max`.\n\nTokens follow the [M3 tooltip spec](https://m3.material.io/components/tooltips/specs). A plain tooltip is `inverse-surface` / `inverse-on-surface`, 4dp corners, `body-small`, 24dp minimum, 4/8dp padding, 200dp max, no elevation and no caret. It sits 4dp from the activator. M3 prefers above.\n\n#### Syntax\n\n```html\n<button type=\"button\" class=\"circle\" aria-label=\"Add\" aria-describedby=\"tip-add-to-album\">\n <span class=\"material-symbols\" aria-hidden=\"true\">add</span>\n <span class=\"tooltip\" id=\"tip-add-to-album\">Add to album</span>\n</button>\n\n<button type=\"button\" class=\"circle\" aria-label=\"Below\" aria-describedby=\"tip-below\">\n <span class=\"material-symbols\" aria-hidden=\"true\">arrow_downward</span>\n <span class=\"tooltip bottom\" id=\"tip-below\">Below</span>\n</button>\n```\n\n#### Options\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| `exitDelay` | Number | `200` | Delay before the tooltip disappears, in milliseconds. |\n| `enterDelay` | Number | `0` | Delay before the tooltip appears, in milliseconds. |\n| `tooltipId` | String | — | Id of an element used as the tooltip body. Set by `data-tooltip-id`. Marks the bubble `rich`. |\n| `text` | String | `''` | Plain-text content. Set by `data-tooltip`. Ignored when `tooltipId` is set. |\n| `margin` | Number | `4` | Distance from the activator, in pixels, not counting `transitionMovement`. M3 is 4dp. |\n| `inDuration` | Number | `250` | Enter transition duration, in milliseconds. |\n| `opacity` | Number | `1` | Opacity of the tooltip when shown. |\n| `outDuration` | Number | `200` | Exit transition duration, in milliseconds. |\n| `position` | String | `'bottom'` | Direction: `'top'`, `'right'`, `'bottom'`, or `'left'`. Set by `data-position`. The CSS-only default is above. |\n| `transitionMovement` | Number | `10` | How far the tooltip moves during its transition, in pixels. |\n\n#### Methods\n\n- `.open()`: `open()` and `open(true)` show the tooltip after its enter delay without requiring hover or focus. `open(false)` uses the automatic behavior and requires hover or focus when the delay ends.\n- `.close()`: Hide the tooltip.\n- `.destroy()`: Destroy the plugin instance and remove its generated tooltip and event handlers. Rich content returns to its authored position and presentation state. Existing description associations are preserved, so the same content can be initialized again.\n\n#### Also documented\n\nThe Tooltips section of the [API reference](https://www.expressivecss.com/llm.md) also covers Rich, JavaScript, Initialization, Properties.\n\n#### Rules\n\nThe following are end-state semantic invariants. The rule IDs come directly from `semantics.json`; keep them when creating component review criterion instances. Author static requirements; verify component-generated state instead of pre-authoring values the runtime owns.\n\n- `css-tooltip-is-described-by`: A .tooltip inside its control is swallowed: with an aria-label present the label wins and the tooltip is never announced, and without one the two run together. Give the tooltip an id and point aria-describedby at it.\n\n#### Guide checks\n\n- Read the full target-version component documentation before using variants, options, methods, or events not shown here.\n- The target version's documentation and source override this generated summary if they disagree.\n"
|
|
169
169
|
}
|
|
170
170
|
]
|
|
171
171
|
}
|