Spec compliance
What the spec checks, ARIA and axe results, Baseline use and size budgets say about md-gb-* components.
How compliance is measured
Link to “How compliance is measured”The numbers on this page come from the repository itself and are regenerated
by node scripts/m3/gen-compliance-page.mjs (--check fails when this page
is stale). The M3 spec is downloaded with npm run m3:update, split into
units (a sentence, list item, table row or image description, each with an
id), and node scripts/m3/spec-checks.mjs --offline records what happens to
each one in .m3-specs/spec-checks/units.json. Only unit counts and ids are
used here, never spec text.
Spec units
Link to “Spec units”A unit is buildable when the classifier scores it at 0.3 or more
(it describes something a component can do, not a caption or designer advice).
Tested units are cited from a *_test.ts file under labs/gb or
scripts/m3 (spec: <unit id>). Excluded units have a written reason in
scripts/m3/exclusions/*.md (spec-exclude:). Tracked units are known
gaps listed in scripts/m3/CHECKLIST.md (spec-gap:). Uncovered units
are buildable, with no status and no test; the target is 0.
| Spec page | Units | Buildable | Tested | Excluded | Tracked | Uncovered |
|---|---|---|---|---|---|---|
all-buttons |
76 | 30 | 10 | 1 | 0 | 0 |
app-bars |
404 | 319 | 104 | 22 | 0 | 0 |
badges |
162 | 135 | 63 | 2 | 0 | 0 |
bottom-sheets |
162 | 134 | 66 | 1 | 0 | 0 |
button-groups |
249 | 210 | 133 | 2 | 0 | 0 |
buttons |
435 | 348 | 173 | 8 | 0 | 0 |
cards |
315 | 243 | 79 | 37 | 0 | 0 |
carousel |
347 | 299 | 97 | 16 | 0 | 0 |
checkbox |
115 | 82 | 45 | 4 | 0 | 0 |
chips |
516 | 397 | 114 | 21 | 0 | 0 |
date-pickers |
424 | 379 | 79 | 11 | 0 | 0 |
dialogs |
328 | 244 | 124 | 19 | 0 | 0 |
divider |
84 | 48 | 20 | 4 | 0 | 0 |
extended-fab |
262 | 194 | 79 | 16 | 0 | 0 |
fab-menu |
227 | 196 | 81 | 24 | 0 | 0 |
floating-action-button |
247 | 183 | 55 | 24 | 0 | 0 |
foundations/building-for-all |
36 | 0 | 0 | 0 | 0 | 0 |
foundations/customization |
48 | 35 | 10 | 2 | 0 | 0 |
foundations/design-tokens |
129 | 36 | 0 | 2 | 0 | 0 |
foundations/designing |
198 | 83 | 0 | 39 | 0 | 0 |
foundations/interaction/gestures |
51 | 27 | 12 | 3 | 0 | 0 |
foundations/interaction/inputs |
131 | 92 | 36 | 24 | 0 | 0 |
foundations/interaction/selection |
63 | 46 | 34 | 0 | 0 | 0 |
foundations/interaction/states |
260 | 193 | 107 | 8 | 0 | 0 |
foundations/layout/bidirectionality-rtl |
120 | 87 | 45 | 8 | 0 | 0 |
foundations/layout/breakpoints |
336 | 218 | 61 | 3 | 0 | 0 |
foundations/layout/canonical-examples |
185 | 99 | 29 | 7 | 0 | 0 |
foundations/layout/grids-spacing |
216 | 58 | 21 | 6 | 0 | 0 |
foundations/layout/layout-overview |
179 | 95 | 17 | 22 | 0 | 0 |
foundations/layout/scaffold |
216 | 172 | 77 | 10 | 0 | 0 |
foundations/overview |
36 | 5 | 0 | 0 | 0 | 0 |
foundations/usability |
205 | 17 | 0 | 1 | 0 | 0 |
icon-buttons |
352 | 292 | 168 | 2 | 0 | 0 |
lists |
577 | 486 | 161 | 35 | 0 | 0 |
loading-indicator |
151 | 102 | 41 | 6 | 0 | 0 |
menus |
391 | 325 | 124 | 35 | 0 | 0 |
navigation-bar |
313 | 259 | 80 | 24 | 0 | 0 |
navigation-drawer |
295 | 256 | 142 | 5 | 0 | 0 |
navigation-rail |
359 | 311 | 134 | 11 | 0 | 0 |
progress-indicators |
220 | 164 | 61 | 3 | 0 | 0 |
radio-button |
127 | 84 | 44 | 8 | 0 | 0 |
search |
367 | 297 | 154 | 13 | 0 | 0 |
segmented-buttons |
193 | 149 | 56 | 0 | 0 | 0 |
side-sheets |
191 | 165 | 97 | 5 | 0 | 0 |
sliders |
292 | 261 | 124 | 0 | 0 | 0 |
snackbar |
199 | 169 | 71 | 1 | 0 | 0 |
split-button |
186 | 155 | 98 | 3 | 0 | 0 |
styles/color/advanced |
143 | 64 | 29 | 0 | 0 | 0 |
styles/color/choosing-a-scheme |
32 | 10 | 3 | 0 | 0 | 0 |
styles/color/dynamic |
90 | 14 | 6 | 5 | 0 | 0 |
styles/color/resources |
9 | 2 | 0 | 1 | 0 | 0 |
styles/color/roles |
219 | 162 | 77 | 64 | 0 | 0 |
styles/color/static |
77 | 10 | 4 | 3 | 0 | 0 |
styles/color/system |
259 | 93 | 39 | 8 | 0 | 0 |
styles/elevation |
136 | 80 | 29 | 13 | 0 | 0 |
styles/icons |
286 | 141 | 30 | 64 | 0 | 0 |
styles/motion/easing-and-duration |
136 | 110 | 61 | 44 | 0 | 0 |
styles/motion/overview |
126 | 75 | 30 | 31 | 0 | 0 |
styles/motion/transitions |
246 | 140 | 47 | 72 | 0 | 0 |
styles/shape |
159 | 77 | 45 | 6 | 0 | 0 |
styles/spacing |
128 | 77 | 22 | 9 | 0 | 0 |
styles/typography |
392 | 126 | 43 | 29 | 0 | 0 |
switch |
200 | 150 | 86 | 5 | 0 | 0 |
tabs |
245 | 206 | 87 | 12 | 0 | 0 |
text-fields |
405 | 358 | 69 | 14 | 0 | 0 |
time-pickers |
365 | 342 | 208 | 2 | 0 | 0 |
toolbars |
339 | 253 | 71 | 23 | 0 | 0 |
tooltips |
162 | 130 | 58 | 0 | 0 | 0 |
| Total | 15,129 | 10,799 | 4,370 | 903 | 0 | 0 |
15,129 units on 68 pages (components: 10,282, foundations: 2,409, styles: 2,438).
Buildable units that are neither tested nor excluded are covered another way:
a citation outside a test, a token value checked by the generated spec tests,
a unit judged covered by the LLM review, or a unit that is not a requirement
(image descriptions, overview notes). Those statuses are in units.json and
.m3-specs/spec-checks/report.md.
Excluded units by reason
Link to “Excluded units by reason”An exclusion is only valid when no code could satisfy the unit (designer advice, app content, platform-only rules). If the library could enforce or default it, it is tracked as a gap instead.
| Reason (from scripts/m3/exclusions) | Units |
|---|---|
| Figure captions, labels and swatch descriptions with no requirement of their own | 124 |
| Figure and video captions | 62 |
| Figure, video and interaction-style captions and spec-table cells with no requirement of their own | 51 |
| Baseline variants the spec no longer recommends for new designs | 43 |
| Accessibility and interaction design guidance for designers and app authors (contrast, touch targ... | 39 |
| Usage advice and rationale for designers (when to pick a pattern, easing, duration or speed | 39 |
| Figure captions and list labels that name an example in a figure (which component or pattern the ... | 33 |
| Usage advice for designers and content guidance for the app author (what to write, when to choose... | 33 |
| Cards | 32 |
| Layout and spacing design guidance (rulers, grid concepts, component adaptation principles, input... | 29 |
| 73 further reasons | 418 |
Token audit
Link to “Token audit”node scripts/m3/audit-gb.mjs --gaps compares every token declaration in the
labs/gb token files with the M3 token database. Match means the value
equals the spec; derived means it is computed from a matching token;
drift differs from the spec; no spec token has no counterpart in the
database; gaps are tokens the Compose reference uses that no gb
declaration implements.
Overall: 2415 declarations, 1949 match, 23 derived, 10 drift (0 high-confidence), 433 with no spec token, 10 spec tokens not implemented.
| Component | Declarations | Match | Derived | Drift | No spec token | Gaps | Unwired |
|---|---|---|---|---|---|---|---|
appbar |
51 | 47 | 0 | 0 | 4 | 4 | 0 |
badge |
11 | 10 | 0 | 0 | 1 | 0 | 0 |
button |
168 | 157 | 1 | 0 | 10 | 0 | 0 |
buttongroup |
36 | 10 | 0 | 0 | 26 | 0 | 0 |
card |
35 | 33 | 0 | 0 | 2 | 0 | 0 |
carousel |
29 | 14 | 0 | 0 | 15 | 0 | 0 |
checkbox |
54 | 43 | 0 | 0 | 11 | 0 | 0 |
chip |
133 | 121 | 0 | 0 | 12 | 0 | 0 |
datepicker |
146 | 112 | 0 | 1 | 33 | 0 | 0 |
dialog |
45 | 41 | 0 | 0 | 4 | 0 | 0 |
divider |
4 | 2 | 0 | 0 | 2 | 0 | 0 |
fab |
65 | 65 | 0 | 0 | 0 | 0 | 0 |
fabmenu |
38 | 36 | 0 | 0 | 2 | 0 | 0 |
iconbutton |
122 | 113 | 1 | 0 | 8 | 0 | 0 |
list |
117 | 101 | 4 | 1 | 11 | 3 | 0 |
loadingindicator |
9 | 7 | 0 | 0 | 2 | 0 | 0 |
menu |
113 | 97 | 0 | 0 | 16 | 0 | 0 |
navbar |
40 | 35 | 0 | 0 | 5 | 0 | 0 |
navdrawer |
57 | 38 | 0 | 1 | 18 | 0 | 0 |
navrail |
92 | 38 | 8 | 0 | 46 | 0 | 0 |
progress |
18 | 17 | 0 | 0 | 1 | 3 | 0 |
radio |
24 | 18 | 0 | 0 | 6 | 0 | 0 |
search |
79 | 60 | 0 | 0 | 19 | 0 | 0 |
segmentedbutton |
23 | 16 | 0 | 0 | 7 | 0 | 0 |
select |
256 | 248 | 0 | 2 | 6 | 0 | 0 |
sheet |
40 | 20 | 0 | 2 | 18 | 0 | 0 |
slider |
52 | 19 | 0 | 3 | 30 | 0 | 0 |
snackbar |
42 | 15 | 1 | 0 | 26 | 0 | 0 |
splitbutton |
53 | 36 | 0 | 0 | 17 | 0 | 0 |
switch |
58 | 53 | 0 | 0 | 5 | 0 | 0 |
tabs |
56 | 40 | 1 | 0 | 15 | 0 | 0 |
textfield |
150 | 130 | 0 | 0 | 20 | 0 | 0 |
timepicker |
95 | 88 | 0 | 0 | 7 | 0 | 0 |
toolbar |
63 | 45 | 7 | 0 | 11 | 0 | 0 |
tooltip |
41 | 24 | 0 | 0 | 17 | 0 | 0 |
Drift
Link to “Drift”Each drift is listed with the token file section, the custom property and why
it differs. E~ is a deliberate // EDIT: override of a generated value;
?~ is an inferred binding that may be wrong (the audit cannot always tell
which spec token a declaration belongs to).
| Component | Section | Property | Reason |
|---|---|---|---|
datepicker |
root |
--menu-list-item-selected-container-color |
deliberate // EDIT: override |
list |
list-tokens.item |
--container-color |
inferred binding that may be wrong |
navdrawer |
root |
--container-shape |
deliberate // EDIT: override |
select |
outlined |
--container-color |
deliberate // EDIT: override |
select |
outlined-autocomplete |
--container-color |
deliberate // EDIT: override |
sheet |
side |
--divider-color |
deliberate // EDIT: override |
sheet |
side-modal |
--container-shape |
deliberate // EDIT: override |
slider |
root |
--active-track-inner-corner-size |
inferred binding that may be wrong |
slider |
root |
--track-shape |
inferred binding that may be wrong |
slider |
disabled |
--stop-indicator-color |
inferred binding that may be wrong |
Accessibility
Link to “Accessibility”Two central suites render rows in labs/gb/components/shared/central and run in a real browser:
- axe (
axe_test.ts): axe-core with no rule disabled, on every subject of the central table (subjects.ts) plus 29 overlay rows in their open state (axe-helpers.ts). - ARIA 1.3 (
aria_test.ts): the axe rows plus 34 rows that put components in the states ARIA depends on (selected, checked, expanded, grouped, with panels, with an error), checked against the WAI-ARIA 1.3 role and attribute rules. 27 rows are open overlays, so the checks that flip state skip them.
Known gaps are rows with a real violation. They move to axe_gap.ts and
aria_gap.ts (red on purpose) and are recorded in AXE_GAPS and
ARIA_GAPS. Today: axe none; ARIA none.
Suite files: aria_gap.ts, aria_test.ts, axe_gap.ts, axe_test.ts.
Baseline
Link to “Baseline”npm run gb:baseline maps every CSS feature in the compiled labs/gb CSS
to its web-features Baseline status. A feature that is not widely available
must sit inside a matching @supports guard or be listed with a reason in
scripts/gb-baseline-allow.json; anything else fails the run.
- CSS: 19,541 feature uses in 62 files; 51 features are not widely available, used 754 times (478 guarded, 276 allowed with a reason, 0 unguarded). Result: passes.
- JavaScript (report only): 31 tracked Web API members in 207 source files; 6 are not widely available, 3 of them with at least one use that is not feature-detected.
Size budgets
Link to “Size budgets”Each component has a Brotli size budget for JavaScript and CSS in
scripts/size/gb-budgets.json: the measured size plus 10% headroom, enforced by
the size check. Totals across 37 components: 345,176 bytes of JavaScript and 77,248 bytes of CSS.
| Component | JS budget (bytes) | CSS budget (bytes) |
|---|---|---|
appbar |
4,639 | 1,586 |
badge |
959 | 474 |
button |
5,485 | 1,508 |
buttongroup |
19,496 | 1,397 |
card |
3,425 | 956 |
carousel |
12,223 | 1,747 |
checkbox |
4,963 | 987 |
chip |
9,624 | 2,417 |
datepicker |
29,548 | 3,889 |
dialog |
9,249 | 2,020 |
divider |
706 | 348 |
fab |
9,723 | 1,097 |
fabmenu |
5,284 | 2,161 |
iconbutton |
10,336 | 1,335 |
list |
13,579 | 3,507 |
loadingindicator |
3,116 | 7,681 |
menu |
10,170 | 2,391 |
navbar |
7,662 | 1,795 |
navdrawer |
9,919 | 2,299 |
navrail |
13,559 | 2,501 |
progress |
3,237 | 3,364 |
pulltorefresh |
6,695 | 1,280 |
radio |
5,224 | 763 |
scaffold |
12,783 | 2,735 |
search |
12,816 | 2,435 |
segmentedbutton |
7,856 | 1,557 |
select |
12,916 | 2,023 |
sheet |
12,922 | 2,367 |
slider |
8,179 | 3,101 |
snackbar |
7,853 | 1,817 |
splitbutton |
3,015 | 986 |
switch |
5,767 | 1,383 |
tabs |
14,838 | 2,281 |
textfield |
7,593 | 2,727 |
timepicker |
13,539 | 3,098 |
toolbar |
20,051 | 1,779 |
tooltip |
6,227 | 1,456 |