@fusion.dev/helix-docs 0.0.0-dev → 0.0.3

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.
Files changed (41) hide show
  1. package/content/browser-support.mdx +2 -2
  2. package/content/charting.mdx +4 -8
  3. package/content/coding-agents.mdx +14 -22
  4. package/content/color-modes.mdx +4 -4
  5. package/content/color.mdx +2 -2
  6. package/content/elevation-and-material.mdx +2 -2
  7. package/content/events.mdx +1 -1
  8. package/content/forms.mdx +5 -7
  9. package/content/iconography.mdx +15 -12
  10. package/content/installation.mdx +4 -6
  11. package/content/introduction.mdx +1 -1
  12. package/content/metrics.mdx +214 -214
  13. package/content/other-frameworks.mdx +6 -5
  14. package/content/overriding-a-component.mdx +11 -15
  15. package/content/routing.mdx +4 -4
  16. package/content/server-rendering.mdx +1 -1
  17. package/content/shape-and-borders.mdx +19 -8
  18. package/content/space-and-size.mdx +1 -1
  19. package/content/state-and-control.mdx +5 -5
  20. package/content/svelte.mdx +3 -3
  21. package/content/theme-builder.mdx +1 -1
  22. package/content/theming.mdx +1 -1
  23. package/content/tiers.mdx +2 -2
  24. package/content/tokens.mdx +4 -4
  25. package/content/using-helix-with-an-agent.mdx +30 -27
  26. package/content/using-the-elements.mdx +0 -2
  27. package/content/visual-axes.mdx +5 -7
  28. package/content/without-a-bundler.mdx +4 -5
  29. package/dist/catalog.d.ts +19 -29
  30. package/dist/catalog.js +27 -49
  31. package/dist/naming.js +1 -1
  32. package/dist/pages.generated.d.ts +1 -1
  33. package/dist/pages.generated.js +1 -1
  34. package/dist/reference.js +1 -1
  35. package/dist/registry.d.ts +3 -3
  36. package/dist/registry.js +3 -3
  37. package/dist/sections.d.ts +3 -7
  38. package/dist/sections.js +3 -7
  39. package/dist/sources.generated.d.ts +2 -2
  40. package/dist/sources.generated.js +367 -374
  41. package/package.json +6 -2
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Every page's MDX, inlined by `bun run docs`. Do not edit: the files in
3
- * `content/` are the source, and `bun run check:docs` fails when this module
2
+ * Every page's MDX, inlined by `turbo run docs`. Do not edit: the files in
3
+ * `content/` are the source, and `turbo run docs -- --check` fails when this module
4
4
  * and they disagree.
5
5
  */
6
6
  export const docSources = {
@@ -213,11 +213,11 @@ report we want, and it is not one we would have caught.
213
213
  | Custom elements and shadow DOM | Everything |
214
214
  | \`ElementInternals\` | Form participation, and ARIA that has to cross a shadow boundary |
215
215
  | Popover API | Every overlay: menu, tooltip, select, combobox, dialog |
216
- | \`light-dark()\` | 761 declarations, 135 of them in the token layer |
216
+ | \`light-dark()\` | 156 declarations in the shipped stylesheets, 71 of them in the token layer |
217
217
  | \`oklch()\` | Every color in the system |
218
218
  | \`:has()\` | 11 rules, mostly relational styling of slotted content |
219
219
  | \`@starting-style\` | Entry transitions on overlays |
220
- | \`:state()\` | Every boolean state the library publishes: \`open\`, \`checked\`, \`selected\`, \`invalid\`, \`read\`, \`has-label\`, \`settled\`, \`empty\` |
220
+ | \`:state()\` | Every boolean state the library publishes: \`open\`, \`checked\`, \`selected\`, \`invalid\`, \`read\`, \`has-label\`, \`settled\`, \`empty\`, \`controls\` |
221
221
  | \`CSS.highlights\` | Filter-match highlighting, in \`Command\` and \`Combobox\` |
222
222
 
223
223
  Positioning is \`@floating-ui/dom\` rather than CSS anchor positioning, which is a
@@ -465,18 +465,14 @@ Hide the table visually if it should not be seen, and the data is still there:
465
465
  The caption becomes the chart's accessible name unless you set \`label\`, which is
466
466
  usually the right words and is already written.
467
467
 
468
- ## Series colours
468
+ ## Series colors
469
469
 
470
470
  Twenty-four \`--helix-color-series-*\` tokens, in order. A chart with three series
471
471
  uses the first three. They are ordered to stay distinguishable in that order
472
472
  rather than to look good as a full set of twenty-four.
473
473
 
474
- The palette wraps, and where it wraps is one number in one place. It used to be
475
- four: four families held the same \`const PALETTE = 24\` and the legend held a
476
- fifth, so when the palette went from eight to twenty-four one of them was missed
477
- and drew every ninth series in the first color while the legend beside it named
478
- the ninth correctly. A number two files have to agree on is a number that will
479
- stop agreeing.
474
+ The palette wraps, and where it wraps is one number in one place, so a chart and
475
+ the legend beside it can never disagree about which color a series is.
480
476
 
481
477
  **A chart's mark carries its own series color as a custom property**, because a
482
478
  chart knows which series a bar belongs to and CSS cannot count it. That is what
@@ -489,7 +485,7 @@ lets you restyle a series from outside without knowing the drawing order.
489
485
  <helix-bar-chart for="revenue"></helix-bar-chart>
490
486
  \`\`\`
491
487
 
492
- The legend reads the same table, so the names and the colours cannot disagree
488
+ The legend reads the same table, so the names and the colors cannot disagree
493
489
  with the chart's. Pointing them at two different tables is the only way to make
494
490
  them disagree, and it is not something to do by accident.
495
491
 
@@ -525,13 +521,9 @@ https://fusion.dev/helix/custom-elements.json
525
521
  @fusion.dev/helix/custom-elements.json
526
522
  \`\`\`
527
523
 
528
- A URL and a package path, the same file either way. **The URL exists because this
529
- page's own argument required it**: an agent that found the library through
530
- \`llms.txt\` has this site and no checkout, and a specifier is reachable from a
531
- \`node_modules\` and from nowhere else. It was only the specifier until 24 Aug 2026,
532
- and the specifier did not resolve either: \`exports\` carried a \`./*\` pattern
533
- pointing at \`./dist/*/index.js\`, so the path two pages recommended was one
534
- \`require.resolve\` refused.
524
+ A URL and a package path, the same file either way. **Both exist because a
525
+ specifier is reachable from a \`node_modules\` and from nowhere else**, and an
526
+ agent that found the library through \`llms.txt\` has this site and no checkout.
535
527
 
536
528
  Every element, every property with its literal type union, every event with its
537
529
  class, every slot, every part, every custom property. It is what the framework
@@ -569,13 +561,13 @@ These are the difference between code that looks right and code that passes:
569
561
 
570
562
  | Rule | Check |
571
563
  |---|---|
572
- | A dispatched event must be declared | \`check:events\` |
573
- | A documented part must be rendered | \`check:parts\` |
574
- | A documented CSS hook must be read | \`check:hooks\` |
575
- | A visual property draws from its axis | \`check:axes\` |
576
- | A form control styles with \`:disabled\` | \`check:disabled\` |
577
- | A component that animates answers reduced motion | \`check:motion\` |
578
- | No component reads a primitive token | \`check:tokens\` |
564
+ | A dispatched event must be declared | \`helix component --only events\` |
565
+ | A documented part must be rendered | \`helix component\`'s \`parts\` |
566
+ | A documented CSS hook must be read | \`helix component --only hooks\` |
567
+ | A visual property draws from its axis | \`helix component\`'s \`axes\` |
568
+ | A form control styles with \`:disabled\` | \`helix component --only disabled\` |
569
+ | A component that animates answers reduced motion | \`helix component --only motion\` |
570
+ | No component reads a primitive token | \`helix component\`'s \`tokens\` |
579
571
 
580
572
  If you are generating Helix code, the first two are the ones that produce
581
573
  working-looking output that is wrong.
@@ -593,8 +585,7 @@ existing.
593
585
 
594
586
  Start there rather than crawling: one request, and it names every page on the
595
587
  site plus the two machine-readable surfaces above. No count here, because a
596
- number typed into prose is a number that goes stale, which the read of these pages
597
- on 24 Aug 2026 found five of.
588
+ number typed into prose is a number that goes stale.
598
589
 
599
590
  ## From a component's page
600
591
 
@@ -634,12 +625,9 @@ of a binary you installed, talking to a client you chose, with no network in it.
634
625
  page into one file is out of date the moment anything changes, where the links
635
626
  in \`llms.txt\` are individually cacheable and individually current.
636
627
 
637
- This page used to offer one anyway, a repository path to a generated document
638
- holding every family at once, which contradicted the paragraph above it and was
639
- not a thing a consumer could open: an agent reading the published package has
640
- this site and no checkout. What it was for is covered better by the two surfaces
641
- already here. \`llms.txt\` is the index, one request, and each family's \`.md\` is
642
- the document. Fetch the families you are using.
628
+ What such a file would be for is covered better by the two surfaces already
629
+ here. \`llms.txt\` is the index, one request, and each family's \`.md\` is the
630
+ document. Fetch the families you are using.
643
631
 
644
632
  **A search index.** The site has one for humans; there is nothing an agent can
645
633
  query yet, and \`llms.txt\` plus the documents it names is a smaller thing to read
@@ -653,7 +641,7 @@ title: Color
653
641
 
654
642
  # Color
655
643
 
656
- Seventy-four of the library's 177 tokens are color, which is most of what a
644
+ Seventy-four of the library's 185 tokens are color, which is most of what a
657
645
  theme is. They are roles rather than values: nothing in Helix is named after
658
646
  what it looks like, because a name like \`--brand-blue-500\` stops being true the
659
647
  moment anybody rethemes.
@@ -728,7 +716,7 @@ pairing a reader has to be able to read.
728
716
  /* Yours to read. */
729
717
  color: var(--helix-color-foreground-muted);
730
718
 
731
- /* Not yours to read, and \`check:tokens\` fails the build on it. */
719
+ /* Not yours to read, and the \`tokens\` rule fails the build on it. */
732
720
  color: var(--_helix-neutral-500);
733
721
  \`\`\`
734
722
 
@@ -760,9 +748,9 @@ stylesheet, no \`.dark\` class to toggle, and nothing to remember to update twic
760
748
 
761
749
  Every token is written once, with both halves in a \`light-dark()\`. Which half
762
750
  resolves is decided by \`color-scheme\` and nothing else, so the mode is a single
763
- inherited property and no token is restated to honor it. That is 761
764
- declarations across the library, 135 of them in the token layer, expressing two
765
- modes without a second copy of anything.
751
+ inherited property and no token is restated to honor it. That is 156
752
+ declarations across the shipped stylesheets, 71 of them in the token layer,
753
+ expressing two modes without a second copy of anything.
766
754
 
767
755
  ## Setting the mode
768
756
 
@@ -812,7 +800,7 @@ told.
812
800
 
813
801
  ## What this means for your own CSS
814
802
 
815
- Write \`light-dark()\` for your own colours and set nothing else:
803
+ Write \`light-dark()\` for your own colors and set nothing else:
816
804
 
817
805
  \`\`\`css
818
806
  .callout {
@@ -1070,8 +1058,8 @@ Eight tokens describing translucency rather than color:
1070
1058
  | \`--helix-material-blur-sm\` | \`8px\` | The lightest backdrop blur. |
1071
1059
  | \`--helix-material-blur-md\` | \`16px\` | The backdrop blur a modal takes. |
1072
1060
  | \`--helix-material-blur-lg\` | \`32px\` | The heaviest backdrop blur. |
1073
- | \`--helix-material-translucent\` | \`color-mix(in oklab, light-dark(oklch(1 0 0), oklch(0.21 var(--helix-seed-neutral-chroma, 0) var(--helix-seed-neutral-hue, 258))) 30%, transparent)\` | The translucent ground, for a surface that admits what is behind it. |
1074
- | \`--helix-material-translucent-strong\` | \`color-mix(in oklab, light-dark(oklch(1 0 0), oklch(0.21 var(--helix-seed-neutral-chroma, 0) var(--helix-seed-neutral-hue, 258))) 88%, transparent)\` | The heavier translucent ground, for one that admits less. |
1061
+ | \`--helix-material-translucent\` | \`color-mix(in oklab, light-dark(oklch(1 0 0), oklch(0.182 var(--helix-seed-neutral-chroma, 0) var(--helix-seed-neutral-hue, 258))) 30%, transparent)\` | The translucent ground, for a surface that admits what is behind it. |
1062
+ | \`--helix-material-translucent-strong\` | \`color-mix(in oklab, light-dark(oklch(1 0 0), oklch(0.182 var(--helix-seed-neutral-chroma, 0) var(--helix-seed-neutral-hue, 258))) 88%, transparent)\` | The heavier translucent ground, for one that admits less. |
1075
1063
  | \`--helix-material-border\` | \`light-dark(color-mix(in oklab, oklch(0.15 var(--helix-seed-neutral-chroma, 0) var(--helix-seed-neutral-hue, 258)) 14%, transparent), color-mix(in oklab, oklch(1 0 0) 12%, transparent))\` | The edge a translucent surface needs to have any at all. |
1076
1064
 
1077
1065
  [//]: # (/tokens)
@@ -1197,7 +1185,7 @@ dispatch, so an event you can listen for is an event that is documented.
1197
1185
  | \`helix-navigate\` | A component is about to navigate |
1198
1186
  | \`helix-copy\` | Something was copied |
1199
1187
  | \`helix-caret\` | The cursor moved in a text control |
1200
- | \`helix-load\`, \`helix-error\`, \`helix-complete\` | Media and async lifecycle |
1188
+ | \`helix-complete\` | A control that fills up has filled |
1201
1189
  | \`helix-create\` | A new item was made from a query |
1202
1190
  | \`helix-console\` | The sandbox relaying a log |
1203
1191
  | \`helix-tour-ask\`, \`helix-sample-start\`, \`helix-sample-end\` | Tour and color sampling |
@@ -1314,7 +1302,7 @@ Submitting an empty form blocks and points at the control. \`checkValidity()\`,
1314
1302
  \`reportValidity()\` and \`:invalid\` behave.
1315
1303
 
1316
1304
  **\`feedback\` overrides the message.** Left empty, the browser's own is shown,
1317
- which is localised and familiar; set, it says what you want in the words your
1305
+ which is localized and familiar; set, it says what you want in the words your
1318
1306
  product uses:
1319
1307
 
1320
1308
  \`\`\`html
@@ -1343,12 +1331,10 @@ deliberately reports no value of its own.
1343
1331
  </fieldset>
1344
1332
  \`\`\`
1345
1333
 
1346
- That works, and it did not always. The platform tells a form-associated element
1347
- through \`formDisabledCallback\`, which nothing implemented, so a control inside a
1348
- disabled fieldset stayed fully typeable and announced itself as enabled.
1349
- Measured: a \`helix-input\` in one accepted text, reported \`disabled\` as false,
1350
- and carried no \`aria-disabled\`, while the form's entry list correctly left it
1351
- out. Interactive and unsubmittable is the worst of both.
1334
+ That works. The platform tells a form-associated element it has been disabled by
1335
+ an ancestor through \`formDisabledCallback\`, and every Helix control implements
1336
+ it, so a control inside a disabled fieldset refuses input and announces itself
1337
+ as off rather than staying typeable and unsubmittable.
1352
1338
 
1353
1339
  **For your own CSS this means one rule.** Style disabled controls with
1354
1340
  \`:disabled\`, never \`[disabled]\`:
@@ -1390,7 +1376,7 @@ returns to, which is usually what a seed in a form means:
1390
1376
  See [State and control](./state-and-control).
1391
1377
  `,
1392
1378
  iconography: `---
1393
- description: 103 glyphs, one geometry, and how to draw one that is not in the set.
1379
+ description: 105 glyphs, one geometry, and how to draw one that is not in the set.
1394
1380
  section: Foundations
1395
1381
  title: Iconography
1396
1382
  ---
@@ -1401,10 +1387,12 @@ title: Iconography
1401
1387
  <helix-icon name="trash"></helix-icon>
1402
1388
  \`\`\`
1403
1389
 
1404
- 103 glyphs, from Phosphor, drawn on a 256 box at stroke-width 16. That is
1390
+ 105 glyphs, from Phosphor, drawn on a 256 box at Phosphor's bold weight. That is
1405
1391
  Phosphor's own geometry and it is kept rather than rescaled: normalizing to a 24
1406
1392
  box would change the optical weight of every glyph and stop the set matching
1407
- anything upstream.
1393
+ anything upstream. Bold rather than regular, because Phosphor's regular is a
1394
+ hairline beside the medium weight this library sets its text in, and an icon
1395
+ that reads lighter than the words next to it is the opposite of a mark.
1408
1396
 
1409
1397
  ## Size and color come from the context
1410
1398
 
@@ -1454,21 +1442,22 @@ failure rather than an empty box.
1454
1442
 
1455
1443
  ## Adding one
1456
1444
 
1457
- Drop the SVG into \`helix/icons/raw\` and run \`bun run icons\`. The set is
1458
- generated from those files, so adding a glyph is adding a file rather than
1459
- hand-transcribing a path into a TypeScript object.
1445
+ Add the name to \`helix/icons/icons.txt\` and run \`turbo run icons\`. Phosphor names
1446
+ resolve from \`@phosphor-icons/core\` at build time, so adding a glyph is adding a
1447
+ line rather than hand-transcribing a path into a TypeScript object.
1460
1448
 
1461
- Keep to the same geometry: 256 box, stroke-width 16, no fill. A glyph drawn at a
1462
- different weight is visible immediately when it sits beside one that was not.
1449
+ A mark Phosphor does not draw goes into \`helix/icons/raw\` as an SVG under the
1450
+ same name, and is read from there when the package has no match. Keep it to the
1451
+ same geometry, a 256 box at the bold weight: a glyph drawn at a different weight
1452
+ is visible immediately when it sits beside one that was not.
1463
1453
 
1464
1454
  ## Icons this set does not have
1465
1455
 
1466
1456
  Product marks. Helix and Cortex have marks and they live in the icon package,
1467
1457
  but a mark is not an icon: it identifies a product and does not mean an action.
1468
- Three earlier attempts at product marks were removed for being pictograms of a
1469
- metaphor standing beside a parent that is a geometric monogram, and the rule
1470
- that replaced them is that **a mark is one rounded body with material removed**.
1471
- If you are reaching for the icon set to draw a logo, that is the wrong drawer.
1458
+ **A mark is one rounded body with material removed**, never a pictogram of a
1459
+ metaphor, because the parent it stands beside is a geometric monogram. If you
1460
+ are reaching for the icon set to draw a logo, that is the wrong drawer.
1472
1461
  `,
1473
1462
  installation: `---
1474
1463
  description: What to install, the order the stylesheets go in, and how to check it worked.
@@ -1496,8 +1485,7 @@ import '@fusion.dev/helix/helix.css'
1496
1485
 
1497
1486
  One import, and it is four files in the order they have to be in:
1498
1487
  \`primitives.css\`, \`tokens.css\`, \`base.css\`, \`elements.css\`. The order is
1499
- load-bearing and the failure is silent, which these instructions demonstrated
1500
- for longer than anyone would like, so it is stated once inside the package
1488
+ load-bearing and the failure is silent, so it is stated once inside the package
1501
1489
  rather than by every consumer.
1502
1490
 
1503
1491
  It resolves \`@fusion.dev/helix-styles\` through this package's own dependency, so
@@ -1513,13 +1501,12 @@ own ramp imports the two they want and skips the bundle.
1513
1501
  - **\`primitives.css\`** is the raw ramp the semantic layer is derived from, and
1514
1502
  it is where the seven \`--helix-seed-*\` knobs are read. Nothing in your own
1515
1503
  code should name a primitive, and leaving the file out is not a way to
1516
- enforce that: \`tokens.css\` refers to one 235 times, so without it every
1504
+ enforce that: \`tokens.css\` refers to one 297 times, so without it every
1517
1505
  semantic token resolves to nothing at all. Measured on a page missing it,
1518
1506
  \`--helix-color-background\` computes to \`rgba(0, 0, 0, 0)\`, and so does every
1519
1507
  other color. It is also the file [theming](theming.mdx) depends on, since a
1520
- \`--helix-seed-brand\` nobody reads moves nothing. **This is the one that was
1521
- missing from this page**, which is why the bundle exists.
1522
- - **\`tokens.css\`** declares the semantic layer, 177 custom properties in 15
1508
+ \`--helix-seed-brand\` nobody reads moves nothing.
1509
+ - **\`tokens.css\`** declares the semantic layer, 185 custom properties in 15
1523
1510
  categories, plus \`color-scheme: light dark\` on \`:root\`. Everything below reads
1524
1511
  from it, and it reads primitives.
1525
1512
  - **\`base.css\`** is the element reset, the type scale on bare \`h1\` through
@@ -1736,7 +1723,7 @@ analysis time rather than left to review.
1736
1723
  bun add @fusion.dev/helix @fusion.dev/helix-styles
1737
1724
  \`\`\`
1738
1725
 
1739
- Three imports at your app root, in this order, then the elements are usable
1726
+ Two imports at your app root, in this order, then the elements are usable
1740
1727
  anywhere:
1741
1728
 
1742
1729
  \`\`\`ts
@@ -1879,7 +1866,7 @@ title: Metrics
1879
1866
 
1880
1867
  # Metrics
1881
1868
 
1882
- *Generated by \`bun run metrics\` from the built packages. Do not edit: every
1869
+ *Generated by \`bun run gen:metrics\` from the built packages. Do not edit: every
1883
1870
  number here is measured, and an edited one is a number nothing produced.*
1884
1871
 
1885
1872
  Bundle size, and what a component costs in time. The two are kept apart on
@@ -1919,7 +1906,7 @@ nobody ever downloads this floor on its own.
1919
1906
 
1920
1907
  | | Raw | Gzip | Brotli |
1921
1908
  |---|---|---|---|
1922
- | Lit and \`@fusion.dev/helix-core\` | 132,955 | 44,397 | 38,019 |
1909
+ | Lit and \`@fusion.dev/helix-core\` | 134,972 | 44,683 | 38,067 |
1923
1910
 
1924
1911
  ## Whole packages
1925
1912
 
@@ -1930,11 +1917,11 @@ repository does that. The per-component tables are what a page pays.
1930
1917
 
1931
1918
  | Package | Raw | Gzip | Brotli | |
1932
1919
  |---|---|---|---|---|
1933
- | \`@fusion.dev/helix-core\` | 132,509 | 43,947 | 37,675 | Element base class, mixins, decorators, floating positioning. |
1934
- | \`@fusion.dev/helix-headless\` | 516,161 | 131,048 | 102,771 | Every headless family, which is what the barrel means. |
1935
- | \`@fusion.dev/helix-icons\` | 46,295 | 14,855 | 12,542 | The whole glyph set. |
1936
- | \`@fusion.dev/helix-theme\` | 3,288 | 1,570 | 1,353 | The derivation engine. Build time for most consumers, runtime for a theme switcher. |
1937
- | \`@fusion.dev/helix\` | 964,531 | 218,272 | 160,502 | Every styled family. |
1920
+ | \`@fusion.dev/helix-core\` | 134,526 | 44,221 | 37,891 | Element base class, mixins, decorators, floating positioning. |
1921
+ | \`@fusion.dev/helix-headless\` | 519,032 | 131,647 | 103,098 | Every headless family, which is what the barrel means. |
1922
+ | \`@fusion.dev/helix-icons\` | 47,484 | 14,907 | 12,553 | The whole glyph set. |
1923
+ | \`@fusion.dev/helix-theme\` | 3,288 | 1,571 | 1,355 | The derivation engine. Build time for most consumers, runtime for a theme switcher. |
1924
+ | \`@fusion.dev/helix\` | 956,589 | 216,783 | 158,845 | Every styled family. |
1938
1925
  | \`lit\` | 15,394 | 6,118 | 5,460 | Not ours. Here so it can be subtracted from every row above it. |
1939
1926
 
1940
1927
  ## The stylesheets
@@ -1947,25 +1934,25 @@ is the whole cost of adopting the base layer on its own.
1947
1934
 
1948
1935
  | File | Raw | Gzip | Brotli | |
1949
1936
  |---|---|---|---|---|
1950
- | \`base.css\` | 23,052 | 3,527 | 3,024 | The base layer. Recipes for markup Helix does not render, usable with no JavaScript at all. |
1951
- | \`elements.css\` | 8,336 | 1,905 | 1,614 | The components' own layer, generated from every family's stylesheet. |
1937
+ | \`base.css\` | 23,145 | 3,556 | 3,065 | The base layer. Recipes for markup Helix does not render, usable with no JavaScript at all. |
1938
+ | \`elements.css\` | 8,290 | 1,875 | 1,600 | The components' own layer, generated from every family's stylesheet. |
1952
1939
  | \`all.css\` | 179 | 142 | 110 | The three above in one import, in the order they have to be in. |
1953
- | \`primitives.css\` | 6,274 | 1,233 | 1,055 | The primitive layer. Private, shipped because \`tokens.css\` resolves into it. |
1954
- | \`tokens.css\` | 19,989 | 2,469 | 2,073 | The 185 semantic tokens. Nothing paints without this. |
1940
+ | \`primitives.css\` | 6,275 | 1,234 | 1,062 | The primitive layer. Private, shipped because \`tokens.css\` resolves into it. |
1941
+ | \`tokens.css\` | 19,989 | 2,467 | 2,073 | The 185 semantic tokens. Nothing paints without this. |
1955
1942
 
1956
1943
  ## What the numbers say
1957
1944
 
1958
- **Most of a first component is the runtime under it.** The median styled family is 13,976 bytes gzipped alone and adds 2,475 to a page that already has Helix on it, so 82 percent of the first one is shared and 18 percent is the component. Ten typical components are one plus nine additions rather than ten of the first number, and the pair of columns below is what lets that be worked out rather than guessed.
1945
+ **Most of a first component is the runtime under it.** The median styled family is 13,974 bytes gzipped alone and adds 2,414 to a page that already has Helix on it, so 83 percent of the first one is shared and 17 percent is the component. Ten typical components are one plus nine additions rather than ten of the first number, and the pair of columns below is what lets that be worked out rather than guessed.
1959
1946
 
1960
- Across the tier: the cheapest is \`code\` at 9,057 gzipped alone, the dearest \`data-table\` at 49,471, over 93 components. Every family at once is 218,272.
1947
+ Across the tier: the cheapest is \`code\` at 9,065 gzipped alone, the dearest \`data-table\` at 49,868, over 93 components. Every family at once is 216,783.
1961
1948
 
1962
- **No family imports a barrel, and \`check:barrels\` is what keeps it that way.** \`@fusion.dev/helix-headless\` is \`sideEffects\` over every module in \`dist\`, which is true of a file that calls \`customElements.define\` and which means a bundler may drop none of it: one \`import { HelixHeadlessButton } from '@fusion.dev/helix-headless'\` costs 131,048 bytes gzipped whatever else the page does, which is 9 times the median family measured above. The styled tier imports the family it extends instead, all 93 of them, and the check refuses the shape rather than the package name, so the rule follows \`sideEffects\` wherever it goes.
1949
+ **No family imports a barrel, and the \`barrels\` rule in \`fusion workspace\` is what keeps it that way.** \`@fusion.dev/helix-headless\` is \`sideEffects\` over every module in \`dist\`, which is true of a file that calls \`customElements.define\` and which means a bundler may drop none of it: one \`import { HelixHeadlessButton } from '@fusion.dev/helix-headless'\` costs 131,647 bytes gzipped whatever else the page does, which is 9 times the median family measured above. The styled tier imports the family it extends instead, all 93 of them, and the check refuses the shape rather than the package name, so the rule follows \`sideEffects\` wherever it goes.
1963
1950
 
1964
- The headless tier never had the problem, and it is the control: \`@fusion.dev/helix-core\` is \`sideEffects: false\`, and a headless family is a median of 16,084 bytes gzipped alone.
1951
+ The headless tier never had the problem, and it is the control: \`@fusion.dev/helix-core\` is \`sideEffects: false\`, and a headless family is a median of 16,187 bytes gzipped alone.
1965
1952
 
1966
1953
  ## Against other systems
1967
1954
 
1968
- Four other libraries of custom elements, pinned and measured on 2026-08-24 by \`bun run metrics:peers\`, which installs them into \`.local\` and bundles them through the harness that produced everything above. **Helix's own rows are measured on every run of \`bun run metrics\`**, so the column that could go stale against this repository is the one that cannot.
1955
+ Four other libraries of custom elements, pinned and measured on 2026-08-24 by \`turbo run peers\`, which installs them into \`.local\` and bundles them through the harness that produced everything above. **Helix's own rows are measured on every run of \`bun run gen:metrics\`**, so the column that could go stale against this repository is the one that cannot.
1969
1956
 
1970
1957
  **Every system here is built on Lit**, so the runtime under the comparison is the same library in every column and what is left is the components. A React component library is not in the table, because comparing a custom element with a React component measures the framework.
1971
1958
 
@@ -1973,43 +1960,43 @@ Four other libraries of custom elements, pinned and measured on 2026-08-24 by \`
1973
1960
 
1974
1961
  | Component | System | Raw | Gzip | Brotli |
1975
1962
  |---|---|---|---|---|
1976
- | \`button\` | **Helix** | 37,328 | 11,515 | 10,158 |
1963
+ | \`button\` | **Helix** | 37,399 | 11,545 | 10,187 |
1977
1964
  | | Carbon | 133,058 | 20,959 | 17,685 |
1978
1965
  | | Material Web | 47,060 | 14,173 | 12,591 |
1979
1966
  | | Shoelace | 62,628 | 18,287 | 15,805 |
1980
1967
  | | Spectrum | 98,792 | 22,045 | 18,674 |
1981
- | \`checkbox\` | **Helix** | 40,872 | 12,578 | 11,068 |
1968
+ | \`checkbox\` | **Helix** | 40,821 | 12,584 | 11,091 |
1982
1969
  | | Carbon | 60,255 | 15,609 | 13,550 |
1983
1970
  | | Material Web | 43,785 | 13,556 | 12,015 |
1984
1971
  | | Shoelace | 47,614 | 15,177 | 13,301 |
1985
1972
  | | Spectrum | 62,492 | 15,437 | 13,481 |
1986
- | \`dialog\` | **Helix** | 34,636 | 11,191 | 9,886 |
1973
+ | \`dialog\` | **Helix** | 34,819 | 11,243 | 9,909 |
1987
1974
  | | Carbon | 510,866 | 67,390 | 39,189 |
1988
1975
  | | Material Web | 34,238 | 11,510 | 10,229 |
1989
1976
  | | Shoelace | 52,754 | 17,698 | 15,554 |
1990
1977
  | | Spectrum | 155,708 | 31,899 | 26,262 |
1991
- | \`radio\` | **Helix** | 43,716 | 12,868 | 11,346 |
1978
+ | \`radio\` | **Helix** | 43,516 | 12,844 | 11,308 |
1992
1979
  | | Carbon | 63,055 | 16,887 | 14,605 |
1993
1980
  | | Material Web | 41,044 | 13,234 | 11,757 |
1994
1981
  | | Shoelace | 34,865 | 12,027 | 10,559 |
1995
1982
  | | Spectrum | 38,685 | 10,660 | 9,370 |
1996
- | \`switch\` | **Helix** | 38,547 | 12,144 | 10,699 |
1983
+ | \`switch\` | **Helix** | 38,603 | 12,160 | 10,668 |
1997
1984
  | | Carbon | 69,423 | 17,127 | 14,764 |
1998
1985
  | | Material Web | 50,155 | 14,577 | 12,935 |
1999
1986
  | | Shoelace | 37,833 | 11,814 | 10,568 |
2000
1987
  | | Spectrum | 62,322 | 15,059 | 13,321 |
2001
- | \`tabs\` | **Helix** | 40,442 | 12,374 | 10,893 |
1988
+ | \`tabs\` | **Helix** | 40,196 | 12,332 | 10,861 |
2002
1989
  | | Carbon | 578,766 | 73,537 | 43,235 |
2003
1990
  | | Material Web | 38,883 | 12,820 | 11,368 |
2004
1991
  | | Shoelace | 54,573 | 17,140 | 15,068 |
2005
1992
  | | Spectrum | 64,875 | 18,298 | 16,283 |
2006
- | \`tooltip\` | **Helix** | 59,436 | 20,247 | 17,886 |
1993
+ | \`tooltip\` | **Helix** | 60,498 | 20,576 | 18,184 |
2007
1994
  | | Carbon | 189,382 | 30,354 | 22,273 |
2008
1995
  | | Material Web | | not shipped | |
2009
1996
  | | Shoelace | 57,412 | 20,220 | 17,933 |
2010
1997
  | | Spectrum | 136,599 | 40,552 | 35,286 |
2011
1998
 
2012
- **Where Helix loses**, which is the half of a comparison table worth reading: \`radio\`, \`switch\`, \`tooltip\`. The largest gap is radio against Spectrum, by 2,208 bytes gzipped. 4 of 28 peer measurements come in under ours.
1999
+ **Where Helix loses**, which is the half of a comparison table worth reading: \`radio\`, \`switch\`, \`tooltip\`. The largest gap is radio against Spectrum, by 2,184 bytes gzipped. 4 of 28 peer measurements come in under ours.
2013
2000
 
2014
2001
  - **Carbon** \`@carbon/web-components@2.61.0\`. Its dialog is Modal, its radio is Radio Button, and its switch is Toggle.
2015
2002
  - **Material Web** \`@material/web@2.5.0\`. Ships no tooltip. Its button is measured as the filled one, there being no single button element.
@@ -2020,7 +2007,7 @@ Every specifier measured is in [\`peers.json\`](https://github.com/project-fusio
2020
2007
 
2021
2008
  ## What it costs in time
2022
2009
 
2023
- Measured on 2026-08-26 by \`bun run metrics:timing\`, which drives a real browser against the built packages. The median of 9 runs each, on one machine.
2010
+ Measured on 2026-08-26 by \`turbo run timings\`, which drives a real browser against the built packages. The median of 9 runs each, on one machine.
2024
2011
 
2025
2012
  **These never join the comparison above, and that is not a hedge.** Bytes are a fact about a package and can be held against anybody else's. A timing is a fact about a page, a machine and a day, so a column of somebody else's milliseconds would be comparing two laptops rather than two libraries.
2026
2013
 
@@ -2054,94 +2041,94 @@ Structure, accessibility, state and form participation. No presentation, and no
2054
2041
 
2055
2042
  | Family | Alone raw | Alone gzip | Alone brotli | Added raw | Added gzip | Added brotli |
2056
2043
  |---|---|---|---|---|---|---|
2057
- | \`accordion\` | 76,223 | 25,761 | 21,340 | 3,227 | 1,222 | 655 |
2058
- | \`announcement\` | 74,254 | 25,126 | 20,904 | 1,374 | 684 | 205 |
2059
- | \`app-header\` | 27,483 | 9,331 | 8,226 | 1,306 | 611 | 203 |
2060
- | \`avatar\` | 28,859 | 9,794 | 8,643 | 2,644 | 1,070 | 582 |
2061
- | \`badge\` | 26,919 | 9,246 | 8,148 | 1,120 | 570 | 195 |
2062
- | \`bar-chart\` | 70,700 | 24,232 | 21,400 | 12,138 | 4,122 | 2,902 |
2063
- | \`blockquote\` | 26,839 | 9,232 | 8,140 | 917 | 523 | 98 |
2064
- | \`breadcrumbs\` | 73,875 | 24,790 | 20,711 | 1,955 | 727 | 354 |
2065
- | \`button\` | 31,158 | 10,389 | 9,175 | 3,167 | 1,125 | 613 |
2066
- | \`button-group\` | 26,832 | 9,170 | 8,068 | 661 | 406 | 108 |
2067
- | \`callout\` | 73,005 | 24,653 | 20,548 | 912 | 524 | 175 |
2068
- | \`card\` | 26,866 | 9,186 | 8,102 | 694 | 420 | 51 |
2069
- | \`carousel\` | 79,754 | 26,720 | 22,285 | 7,686 | 2,448 | 1,616 |
2070
- | \`chat\` | 83,713 | 27,957 | 23,221 | 9,449 | 2,829 | 1,918 |
2071
- | \`checkbox\` | 34,492 | 11,126 | 9,843 | 2,252 | 1,011 | 371 |
2072
- | \`checkbox-group\` | 37,392 | 11,749 | 10,393 | 4,655 | 1,633 | 878 |
2073
- | \`code\` | 25,451 | 8,754 | 7,715 | 451 | 292 | 9 |
2074
- | \`code-block\` | 111,326 | 37,528 | 31,778 | 12,439 | 3,555 | 2,534 |
2075
- | \`color-input\` | 129,288 | 42,299 | 35,792 | 26,102 | 7,166 | 5,692 |
2076
- | \`color-picker\` | 99,094 | 32,311 | 26,815 | 19,492 | 5,690 | 4,497 |
2077
- | \`combobox\` | 125,346 | 40,786 | 34,413 | 20,361 | 5,532 | 4,171 |
2078
- | \`command\` | 99,183 | 31,859 | 26,261 | 17,134 | 4,872 | 3,598 |
2079
- | \`copy-button\` | 110,006 | 37,256 | 31,540 | 11,120 | 3,302 | 2,246 |
2080
- | \`data-table\` | 141,668 | 45,322 | 38,167 | 37,185 | 9,848 | 7,800 |
2081
- | \`date-input\` | 122,127 | 40,161 | 33,994 | 19,388 | 5,390 | 4,091 |
2082
- | \`date-picker\` | 84,476 | 28,217 | 23,393 | 9,805 | 3,185 | 2,227 |
2083
- | \`dialog\` | 30,301 | 10,183 | 8,978 | 2,534 | 1,081 | 560 |
2084
- | \`divider\` | 27,036 | 9,308 | 8,172 | 1,115 | 596 | 170 |
2085
- | \`donut-chart\` | 66,610 | 22,813 | 20,207 | 9,398 | 3,290 | 2,302 |
2086
- | \`drawer\` | 29,268 | 9,876 | 8,699 | 1,792 | 798 | 355 |
2087
- | \`drilldown\` | 79,507 | 26,788 | 22,064 | 5,059 | 1,765 | 1,078 |
2088
- | \`empty\` | 26,988 | 9,226 | 8,147 | 816 | 473 | 74 |
2089
- | \`file-input\` | 84,086 | 28,154 | 23,166 | 6,219 | 2,205 | 1,428 |
2090
- | \`format-date\` | 30,257 | 10,284 | 9,103 | 2,805 | 972 | 520 |
2091
- | \`heatmap\` | 68,075 | 23,096 | 20,397 | 10,692 | 3,537 | 2,391 |
2092
- | \`icon\` | 72,411 | 24,410 | 20,339 | 850 | 487 | 75 |
2093
- | \`icon-button\` | 31,557 | 10,419 | 9,198 | 3,566 | 1,153 | 661 |
2094
- | \`image\` | 28,816 | 9,694 | 8,539 | 2,969 | 1,059 | 606 |
2095
- | \`input\` | 83,600 | 27,860 | 22,929 | 4,944 | 1,773 | 1,074 |
2096
- | \`kbd\` | 28,236 | 9,743 | 8,582 | 2,427 | 1,131 | 568 |
2097
- | \`legend\` | 29,187 | 10,066 | 8,845 | 1,097 | 600 | 176 |
2098
- | \`line-chart\` | 68,726 | 23,631 | 20,885 | 10,165 | 3,525 | 2,540 |
2099
- | \`list\` | 27,887 | 9,356 | 8,240 | 1,727 | 588 | 278 |
2100
- | \`listbox\` | 91,239 | 30,089 | 24,864 | 10,677 | 3,397 | 2,343 |
2101
- | \`loader\` | 27,072 | 9,293 | 8,182 | 900 | 503 | 64 |
2102
- | \`megamenu\` | 55,180 | 19,332 | 17,079 | 4,934 | 1,741 | 1,043 |
2103
- | \`menu\` | 108,430 | 36,763 | 31,227 | 8,105 | 2,390 | 1,596 |
2104
- | \`meter\` | 29,964 | 10,078 | 8,894 | 3,800 | 1,271 | 786 |
2105
- | \`navigation\` | 28,831 | 9,815 | 8,680 | 1,582 | 720 | 218 |
2106
- | \`notifications\` | 83,706 | 28,017 | 23,156 | 8,640 | 2,592 | 1,723 |
2107
- | \`number-input\` | 85,670 | 28,393 | 23,470 | 7,100 | 2,322 | 1,489 |
2108
- | \`option\` | 28,849 | 9,632 | 8,502 | 2,680 | 896 | 466 |
2109
- | \`outline\` | 31,837 | 10,814 | 9,540 | 4,539 | 1,772 | 1,039 |
2110
- | \`pagination\` | 130,381 | 41,800 | 35,277 | 26,097 | 6,594 | 5,115 |
2111
- | \`pin-input\` | 37,381 | 11,959 | 10,576 | 5,135 | 1,862 | 1,159 |
2112
- | \`popover\` | 52,511 | 18,611 | 16,413 | 2,019 | 873 | 397 |
2113
- | \`progress\` | 28,113 | 9,563 | 8,430 | 1,949 | 788 | 421 |
2114
- | \`qr-code\` | 38,587 | 13,556 | 11,956 | 12,807 | 4,961 | 4,012 |
2115
- | \`quote\` | 26,355 | 9,041 | 7,964 | 552 | 402 | 103 |
2116
- | \`radio\` | 35,977 | 11,448 | 10,083 | 3,138 | 1,162 | 529 |
2117
- | \`rating\` | 38,033 | 12,237 | 10,822 | 5,617 | 2,031 | 1,258 |
2118
- | \`scroll-area\` | 28,463 | 9,741 | 8,560 | 2,610 | 1,108 | 492 |
2119
- | \`select\` | 119,544 | 39,510 | 33,314 | 15,389 | 4,432 | 3,180 |
2120
- | \`skeleton\` | 25,544 | 8,786 | 7,725 | 544 | 354 | 6 |
2121
- | \`slider\` | 37,742 | 12,019 | 10,633 | 5,250 | 1,817 | 1,153 |
2122
- | \`sparkline\` | 31,645 | 11,086 | 9,794 | 2,530 | 1,085 | 618 |
2123
- | \`speed-dial\` | 100,991 | 34,766 | 29,474 | 3,821 | 1,299 | 714 |
2124
- | \`splitter\` | 36,329 | 11,666 | 10,300 | 10,165 | 2,926 | 2,149 |
2125
- | \`stat\` | 27,320 | 9,222 | 8,136 | 1,150 | 459 | 85 |
2126
- | \`steps\` | 81,596 | 27,126 | 22,419 | 6,303 | 1,864 | 1,145 |
2127
- | \`switch\` | 34,160 | 11,058 | 9,766 | 1,798 | 860 | 336 |
2128
- | \`table\` | 31,609 | 10,196 | 9,008 | 4,118 | 1,226 | 758 |
2129
- | \`tabs\` | 33,935 | 11,037 | 9,724 | 4,469 | 1,303 | 719 |
2130
- | \`tag\` | 73,289 | 24,733 | 20,562 | 897 | 492 | 128 |
2131
- | \`textarea\` | 36,847 | 11,696 | 10,315 | 4,115 | 1,416 | 757 |
2132
- | \`time-input\` | 134,184 | 43,285 | 36,521 | 28,643 | 7,663 | 6,078 |
2133
- | \`time-picker\` | 99,260 | 32,521 | 26,869 | 18,154 | 5,510 | 4,100 |
2134
- | \`timeline\` | 73,821 | 24,751 | 20,746 | 1,896 | 686 | 324 |
2135
- | \`toast\` | 77,019 | 25,851 | 21,418 | 4,007 | 1,278 | 790 |
2136
- | \`toggle\` | 38,209 | 12,108 | 10,665 | 3,928 | 1,330 | 703 |
2137
- | \`toolbar\` | 28,734 | 9,827 | 8,655 | 2,932 | 1,258 | 610 |
2138
- | \`tooltip\` | 55,871 | 19,441 | 17,199 | 5,867 | 2,058 | 1,213 |
2139
- | \`tour\` | 61,086 | 20,604 | 18,240 | 10,277 | 2,947 | 2,027 |
2140
- | \`tree\` | 83,288 | 27,803 | 22,913 | 7,069 | 2,379 | 1,471 |
2141
- | \`trend\` | 72,614 | 24,511 | 20,430 | 1,056 | 561 | 140 |
2142
- | \`video\` | 131,880 | 42,504 | 36,213 | 31,304 | 7,765 | 6,491 |
2143
- | \`video-playlist\` | 115,879 | 38,435 | 32,636 | 14,151 | 3,705 | 2,679 |
2144
- | \`virtual-list\` | 29,714 | 10,244 | 9,021 | 2,089 | 964 | 480 |
2044
+ | \`accordion\` | 77,373 | 25,790 | 21,229 | 3,227 | 1,191 | 689 |
2045
+ | \`announcement\` | 75,404 | 25,148 | 20,701 | 1,374 | 658 | 330 |
2046
+ | \`app-header\` | 27,425 | 9,322 | 8,205 | 1,248 | 581 | 264 |
2047
+ | \`avatar\` | 28,859 | 9,794 | 8,642 | 2,644 | 1,039 | 606 |
2048
+ | \`badge\` | 26,919 | 9,246 | 8,163 | 1,120 | 547 | 298 |
2049
+ | \`bar-chart\` | 71,762 | 24,550 | 21,745 | 12,487 | 4,215 | 3,012 |
2050
+ | \`blockquote\` | 26,839 | 9,232 | 8,140 | 917 | 486 | 238 |
2051
+ | \`breadcrumbs\` | 75,025 | 24,814 | 20,607 | 1,955 | 703 | 408 |
2052
+ | \`button\` | 31,312 | 10,445 | 9,216 | 3,167 | 1,103 | 679 |
2053
+ | \`button-group\` | 26,832 | 9,170 | 8,068 | 661 | 386 | 96 |
2054
+ | \`callout\` | 74,155 | 24,675 | 20,454 | 912 | 499 | 245 |
2055
+ | \`card\` | 26,866 | 9,186 | 8,102 | 694 | 393 | 100 |
2056
+ | \`carousel\` | 80,904 | 26,737 | 22,141 | 7,686 | 2,419 | 1,636 |
2057
+ | \`chat\` | 84,863 | 27,980 | 23,052 | 9,449 | 2,818 | 1,981 |
2058
+ | \`checkbox\` | 34,646 | 11,172 | 9,831 | 2,252 | 977 | 459 |
2059
+ | \`checkbox-group\` | 37,546 | 11,793 | 10,407 | 4,655 | 1,615 | 961 |
2060
+ | \`code\` | 25,451 | 8,754 | 7,715 | 451 | 280 | 126 |
2061
+ | \`code-block\` | 113,692 | 37,922 | 32,016 | 12,788 | 3,653 | 2,656 |
2062
+ | \`color-input\` | 131,269 | 42,548 | 35,825 | 26,066 | 7,146 | 5,816 |
2063
+ | \`color-picker\` | 100,398 | 32,385 | 26,772 | 19,492 | 5,706 | 4,527 |
2064
+ | \`combobox\` | 127,329 | 41,037 | 34,567 | 20,327 | 5,495 | 4,250 |
2065
+ | \`command\` | 100,670 | 32,023 | 26,366 | 17,317 | 4,912 | 3,765 |
2066
+ | \`copy-button\` | 112,372 | 37,654 | 31,723 | 11,469 | 3,400 | 2,482 |
2067
+ | \`data-table\` | 143,864 | 45,643 | 38,407 | 37,364 | 9,893 | 7,960 |
2068
+ | \`date-input\` | 124,144 | 40,441 | 34,068 | 19,388 | 5,371 | 4,207 |
2069
+ | \`date-picker\` | 85,626 | 28,231 | 23,302 | 9,805 | 3,138 | 2,316 |
2070
+ | \`dialog\` | 30,484 | 10,235 | 9,019 | 2,717 | 1,112 | 734 |
2071
+ | \`divider\` | 27,036 | 9,307 | 8,174 | 1,115 | 567 | 227 |
2072
+ | \`donut-chart\` | 67,672 | 23,131 | 20,446 | 9,747 | 3,379 | 2,367 |
2073
+ | \`drawer\` | 29,268 | 9,874 | 8,685 | 1,792 | 774 | 440 |
2074
+ | \`drilldown\` | 80,657 | 26,804 | 22,019 | 5,059 | 1,740 | 1,144 |
2075
+ | \`empty\` | 26,988 | 9,226 | 8,147 | 816 | 448 | 183 |
2076
+ | \`file-input\` | 85,388 | 28,229 | 23,148 | 6,217 | 2,172 | 1,468 |
2077
+ | \`format-date\` | 30,257 | 10,284 | 9,103 | 2,805 | 940 | 531 |
2078
+ | \`heatmap\` | 69,136 | 23,403 | 20,696 | 11,040 | 3,623 | 2,602 |
2079
+ | \`icon\` | 73,561 | 24,431 | 20,290 | 850 | 450 | 184 |
2080
+ | \`icon-button\` | 31,711 | 10,475 | 9,230 | 3,566 | 1,129 | 709 |
2081
+ | \`image\` | 28,816 | 9,691 | 8,518 | 2,969 | 1,030 | 655 |
2082
+ | \`input\` | 84,757 | 27,868 | 22,877 | 4,797 | 1,672 | 1,142 |
2083
+ | \`kbd\` | 28,706 | 9,926 | 8,748 | 2,897 | 1,293 | 870 |
2084
+ | \`legend\` | 29,187 | 10,066 | 8,845 | 1,097 | 577 | 235 |
2085
+ | \`line-chart\` | 69,788 | 23,947 | 21,209 | 10,514 | 3,619 | 2,633 |
2086
+ | \`list\` | 27,887 | 9,360 | 8,245 | 1,727 | 579 | 292 |
2087
+ | \`listbox\` | 92,543 | 30,186 | 24,704 | 10,677 | 3,391 | 2,393 |
2088
+ | \`loader\` | 27,072 | 9,293 | 8,182 | 900 | 475 | 143 |
2089
+ | \`megamenu\` | 55,893 | 19,552 | 17,265 | 4,934 | 1,728 | 1,178 |
2090
+ | \`menu\` | 110,293 | 37,007 | 31,290 | 8,105 | 2,374 | 1,645 |
2091
+ | \`meter\` | 29,964 | 10,079 | 8,879 | 3,800 | 1,234 | 880 |
2092
+ | \`navigation\` | 28,831 | 9,815 | 8,680 | 1,582 | 685 | 347 |
2093
+ | \`notifications\` | 84,856 | 28,045 | 23,078 | 8,640 | 2,567 | 1,892 |
2094
+ | \`number-input\` | 86,974 | 28,468 | 23,363 | 7,100 | 2,293 | 1,618 |
2095
+ | \`option\` | 28,849 | 9,639 | 8,506 | 2,680 | 872 | 552 |
2096
+ | \`outline\` | 31,837 | 10,811 | 9,517 | 4,539 | 1,759 | 1,115 |
2097
+ | \`pagination\` | 132,398 | 42,069 | 35,542 | 26,097 | 6,582 | 5,162 |
2098
+ | \`pin-input\` | 37,535 | 12,009 | 10,627 | 5,135 | 1,841 | 1,219 |
2099
+ | \`popover\` | 53,190 | 18,820 | 16,606 | 1,985 | 825 | 427 |
2100
+ | \`progress\` | 28,113 | 9,566 | 8,450 | 1,949 | 759 | 507 |
2101
+ | \`qr-code\` | 38,587 | 13,554 | 11,997 | 12,807 | 4,944 | 4,132 |
2102
+ | \`quote\` | 26,355 | 9,041 | 7,964 | 552 | 371 | 135 |
2103
+ | \`radio\` | 35,977 | 11,448 | 10,088 | 3,138 | 1,130 | 692 |
2104
+ | \`rating\` | 38,033 | 12,238 | 10,784 | 5,617 | 2,008 | 1,288 |
2105
+ | \`scroll-area\` | 28,465 | 9,748 | 8,556 | 2,612 | 1,073 | 632 |
2106
+ | \`select\` | 121,561 | 39,765 | 33,471 | 15,389 | 4,421 | 3,267 |
2107
+ | \`skeleton\` | 25,544 | 8,786 | 7,725 | 544 | 330 | 72 |
2108
+ | \`slider\` | 37,896 | 12,065 | 10,659 | 5,250 | 1,807 | 1,286 |
2109
+ | \`sparkline\` | 31,645 | 11,088 | 9,794 | 2,530 | 1,054 | 773 |
2110
+ | \`speed-dial\` | 102,854 | 35,015 | 29,681 | 3,821 | 1,260 | 786 |
2111
+ | \`splitter\` | 36,329 | 11,667 | 10,338 | 10,165 | 2,907 | 2,207 |
2112
+ | \`stat\` | 27,320 | 9,222 | 8,136 | 1,150 | 437 | 205 |
2113
+ | \`steps\` | 82,900 | 27,205 | 22,347 | 6,303 | 1,836 | 1,248 |
2114
+ | \`switch\` | 34,314 | 11,106 | 9,826 | 1,798 | 839 | 376 |
2115
+ | \`table\` | 31,861 | 10,274 | 9,086 | 4,373 | 1,285 | 854 |
2116
+ | \`tabs\` | 33,935 | 11,035 | 9,722 | 4,469 | 1,273 | 781 |
2117
+ | \`tag\` | 74,439 | 24,760 | 20,435 | 897 | 472 | 253 |
2118
+ | \`textarea\` | 37,001 | 11,743 | 10,362 | 4,115 | 1,412 | 892 |
2119
+ | \`time-input\` | 136,201 | 43,547 | 36,687 | 28,643 | 7,660 | 6,042 |
2120
+ | \`time-picker\` | 100,564 | 32,606 | 26,818 | 18,154 | 5,497 | 4,221 |
2121
+ | \`timeline\` | 74,971 | 24,767 | 20,563 | 1,896 | 666 | 359 |
2122
+ | \`toast\` | 78,169 | 25,872 | 21,292 | 4,007 | 1,246 | 750 |
2123
+ | \`toggle\` | 38,209 | 12,101 | 10,670 | 3,928 | 1,315 | 828 |
2124
+ | \`toolbar\` | 28,734 | 9,827 | 8,655 | 2,932 | 1,238 | 676 |
2125
+ | \`tooltip\` | 56,933 | 19,770 | 17,504 | 6,216 | 2,147 | 1,428 |
2126
+ | \`tour\` | 61,953 | 20,875 | 18,482 | 10,277 | 2,940 | 2,122 |
2127
+ | \`tree\` | 84,423 | 27,823 | 22,815 | 7,054 | 2,342 | 1,593 |
2128
+ | \`trend\` | 73,764 | 24,534 | 20,358 | 1,056 | 535 | 320 |
2129
+ | \`video\` | 133,542 | 42,701 | 36,225 | 31,103 | 7,713 | 6,441 |
2130
+ | \`video-playlist\` | 117,742 | 38,672 | 32,725 | 14,151 | 3,686 | 2,752 |
2131
+ | \`virtual-list\` | 29,714 | 10,244 | 9,021 | 2,089 | 937 | 604 |
2145
2132
 
2146
2133
  ### Styled tier
2147
2134
 
@@ -2149,99 +2136,99 @@ The headless tier plus presentation. This is what \`bun add @fusion.dev/helix\`
2149
2136
 
2150
2137
  | Family | Alone raw | Alone gzip | Alone brotli | Added raw | Added gzip | Added brotli |
2151
2138
  |---|---|---|---|---|---|---|
2152
- | \`accordion\` | 79,518 | 26,569 | 21,911 | 6,510 | 2,049 | 1,327 |
2153
- | \`announcement\` | 78,022 | 26,038 | 21,534 | 5,126 | 1,535 | 995 |
2154
- | \`app-header\` | 30,814 | 10,122 | 8,910 | 4,620 | 1,375 | 845 |
2155
- | \`aura\` | 93,124 | 32,615 | 28,199 | 66,161 | 23,230 | 20,023 |
2156
- | \`avatar\` | 32,433 | 10,538 | 9,282 | 6,205 | 1,798 | 1,187 |
2157
- | \`badge\` | 29,550 | 9,942 | 8,737 | 3,734 | 1,211 | 784 |
2158
- | \`bar-chart\` | 86,453 | 26,999 | 23,818 | 27,871 | 6,944 | 5,289 |
2159
- | \`blockquote\` | 28,015 | 9,529 | 8,383 | 2,077 | 793 | 367 |
2160
- | \`breadcrumbs\` | 77,346 | 25,597 | 21,315 | 5,414 | 1,491 | 1,010 |
2161
- | \`button\` | 37,328 | 11,515 | 10,158 | 9,319 | 2,274 | 1,635 |
2162
- | \`button-group\` | 28,508 | 9,543 | 8,424 | 2,320 | 783 | 404 |
2163
- | \`callout\` | 75,023 | 25,222 | 20,989 | 2,914 | 1,037 | 632 |
2164
- | \`card\` | 30,062 | 9,999 | 8,796 | 3,878 | 1,197 | 857 |
2165
- | \`carousel\` | 88,795 | 28,265 | 23,685 | 16,716 | 3,981 | 2,976 |
2166
- | \`chat\` | 95,392 | 30,099 | 25,048 | 21,117 | 4,948 | 3,809 |
2167
- | \`checkbox\` | 40,872 | 12,578 | 11,068 | 8,616 | 2,460 | 1,714 |
2168
- | \`checkbox-group\` | 39,639 | 12,321 | 10,884 | 6,888 | 2,215 | 1,375 |
2169
- | \`code\` | 26,476 | 9,057 | 7,994 | 1,459 | 598 | 175 |
2170
- | \`code-block\` | 124,510 | 39,736 | 33,611 | 25,604 | 5,672 | 4,385 |
2171
- | \`color-input\` | 161,123 | 47,164 | 40,047 | 57,917 | 11,996 | 10,000 |
2172
- | \`color-picker\` | 125,641 | 36,555 | 30,553 | 46,033 | 9,895 | 8,289 |
2173
- | \`combobox\` | 139,026 | 43,268 | 36,586 | 34,020 | 7,937 | 6,234 |
2174
- | \`command\` | 109,436 | 33,866 | 28,080 | 27,372 | 6,828 | 5,298 |
2175
- | \`copy-button\` | 120,632 | 39,134 | 33,084 | 21,728 | 5,089 | 3,840 |
2176
- | \`data-table\` | 169,562 | 49,471 | 41,812 | 65,060 | 14,048 | 11,315 |
2177
- | \`date-input\` | 137,056 | 43,024 | 36,502 | 34,295 | 8,187 | 6,693 |
2178
- | \`date-picker\` | 90,171 | 29,433 | 24,478 | 15,482 | 4,357 | 3,290 |
2179
- | \`dialog\` | 34,636 | 11,191 | 9,886 | 6,854 | 2,117 | 1,412 |
2180
- | \`divider\` | 29,181 | 9,821 | 8,631 | 3,243 | 1,074 | 656 |
2181
- | \`donut-chart\` | 78,627 | 24,829 | 21,927 | 21,398 | 5,370 | 3,962 |
2182
- | \`drawer\` | 33,215 | 10,783 | 9,504 | 5,721 | 1,692 | 1,135 |
2183
- | \`drilldown\` | 83,865 | 27,759 | 22,977 | 9,404 | 2,737 | 1,944 |
2184
- | \`empty\` | 28,295 | 9,601 | 8,463 | 2,107 | 826 | 412 |
2185
- | \`file-input\` | 94,830 | 30,332 | 25,049 | 16,956 | 4,366 | 3,243 |
2186
- | \`flex\` | 27,799 | 9,391 | 8,289 | 1,986 | 698 | 351 |
2187
- | \`format-date\` | 30,905 | 10,420 | 9,233 | 3,435 | 1,135 | 531 |
2188
- | \`grid\` | 28,326 | 9,563 | 8,437 | 2,511 | 871 | 525 |
2189
- | \`heatmap\` | 71,868 | 23,944 | 21,216 | 14,467 | 4,404 | 3,164 |
2190
- | \`icon\` | 73,106 | 24,587 | 20,429 | 1,528 | 627 | 270 |
2191
- | \`icon-button\` | 37,656 | 11,455 | 10,088 | 9,651 | 2,208 | 1,604 |
2192
- | \`image\` | 30,646 | 10,202 | 8,977 | 4,781 | 1,555 | 1,038 |
2193
- | \`input\` | 89,818 | 29,243 | 24,183 | 11,157 | 3,138 | 2,169 |
2194
- | \`kbd\` | 29,648 | 10,205 | 8,982 | 3,824 | 1,584 | 1,038 |
2195
- | \`legend\` | 34,022 | 11,144 | 9,798 | 5,924 | 1,707 | 1,104 |
2196
- | \`line-chart\` | 81,226 | 25,771 | 22,754 | 22,646 | 5,721 | 4,207 |
2197
- | \`list\` | 31,940 | 10,289 | 9,061 | 5,770 | 1,526 | 1,095 |
2198
- | \`listbox\` | 95,298 | 31,052 | 25,548 | 14,723 | 4,350 | 3,093 |
2199
- | \`loader\` | 30,078 | 10,033 | 8,831 | 3,891 | 1,192 | 862 |
2200
- | \`megamenu\` | 59,602 | 20,377 | 18,025 | 9,341 | 2,802 | 2,020 |
2201
- | \`menu\` | 114,709 | 38,183 | 32,425 | 14,366 | 3,748 | 2,813 |
2202
- | \`meter\` | 35,602 | 11,267 | 9,972 | 9,420 | 2,475 | 1,903 |
2203
- | \`navigation\` | 30,359 | 10,243 | 9,007 | 3,094 | 1,127 | 575 |
2204
- | \`notifications\` | 91,354 | 29,582 | 24,616 | 16,275 | 4,146 | 3,062 |
2205
- | \`number-input\` | 90,634 | 29,544 | 24,415 | 12,050 | 3,439 | 2,486 |
2206
- | \`option\` | 32,116 | 10,542 | 9,321 | 5,935 | 1,785 | 1,141 |
2207
- | \`outline\` | 35,824 | 11,618 | 10,255 | 8,509 | 2,589 | 1,722 |
2208
- | \`pagination\` | 148,273 | 44,851 | 37,991 | 43,971 | 9,539 | 7,685 |
2209
- | \`pin-input\` | 40,603 | 12,787 | 11,279 | 8,340 | 2,707 | 1,832 |
2210
- | \`popover\` | 55,129 | 19,245 | 17,022 | 4,619 | 1,500 | 983 |
2211
- | \`progress\` | 33,246 | 10,757 | 9,521 | 7,064 | 1,972 | 1,448 |
2212
- | \`qr-code\` | 40,238 | 13,976 | 12,338 | 14,441 | 5,391 | 4,349 |
2213
- | \`quote\` | 27,030 | 9,207 | 8,088 | 1,211 | 570 | 159 |
2214
- | \`radio\` | 43,716 | 12,868 | 11,346 | 10,869 | 2,616 | 1,892 |
2215
- | \`rating\` | 41,008 | 13,168 | 11,593 | 8,574 | 2,951 | 2,075 |
2216
- | \`sandbox\` | 61,201 | 16,813 | 14,897 | 34,739 | 8,029 | 6,423 |
2217
- | \`scroll-area\` | 31,437 | 10,374 | 9,095 | 5,567 | 1,762 | 1,019 |
2218
- | \`select\` | 131,872 | 41,805 | 35,381 | 27,696 | 6,674 | 5,111 |
2219
- | \`skeleton\` | 28,062 | 9,544 | 8,416 | 2,242 | 860 | 426 |
2220
- | \`slider\` | 47,682 | 13,817 | 12,221 | 15,173 | 3,610 | 2,730 |
2221
- | \`sparkline\` | 35,412 | 12,013 | 10,609 | 6,285 | 2,018 | 1,464 |
2222
- | \`speed-dial\` | 108,524 | 36,260 | 30,765 | 11,332 | 2,750 | 2,014 |
2223
- | \`splitter\` | 42,741 | 12,722 | 11,288 | 16,559 | 3,995 | 3,131 |
2224
- | \`stat\` | 29,954 | 9,789 | 8,646 | 3,774 | 1,039 | 614 |
2225
- | \`steps\` | 95,132 | 29,536 | 24,464 | 19,827 | 4,267 | 3,406 |
2226
- | \`switch\` | 38,547 | 12,144 | 10,699 | 6,170 | 1,934 | 1,308 |
2227
- | \`table\` | 34,938 | 10,790 | 9,513 | 7,436 | 1,842 | 1,199 |
2228
- | \`tabs\` | 40,442 | 12,374 | 10,893 | 10,965 | 2,669 | 1,847 |
2229
- | \`tag\` | 76,483 | 25,615 | 21,389 | 4,076 | 1,285 | 897 |
2230
- | \`text\` | 29,734 | 9,670 | 8,508 | 3,922 | 994 | 512 |
2231
- | \`textarea\` | 40,278 | 12,528 | 11,028 | 7,529 | 2,288 | 1,518 |
2232
- | \`time-input\` | 154,142 | 46,671 | 39,499 | 48,582 | 10,985 | 8,883 |
2233
- | \`time-picker\` | 110,619 | 34,662 | 28,765 | 29,508 | 7,635 | 5,964 |
2234
- | \`timeline\` | 77,087 | 25,507 | 21,266 | 5,151 | 1,394 | 978 |
2235
- | \`toast\` | 84,299 | 27,460 | 22,823 | 11,274 | 2,899 | 2,145 |
2236
- | \`toggle\` | 43,388 | 13,293 | 11,734 | 9,099 | 2,562 | 1,840 |
2237
- | \`toolbar\` | 29,632 | 10,054 | 8,841 | 3,813 | 1,495 | 838 |
2238
- | \`tooltip\` | 59,436 | 20,247 | 17,886 | 9,414 | 2,863 | 1,933 |
2239
- | \`tour\` | 71,124 | 22,307 | 19,738 | 20,296 | 4,649 | 3,493 |
2240
- | \`tree\` | 88,512 | 29,043 | 24,005 | 12,281 | 3,611 | 2,628 |
2241
- | \`trend\` | 75,648 | 25,206 | 21,009 | 4,083 | 1,215 | 769 |
2242
- | \`video\` | 149,490 | 45,696 | 38,857 | 48,893 | 10,889 | 9,107 |
2243
- | \`video-playlist\` | 128,650 | 40,737 | 34,547 | 26,903 | 5,922 | 4,697 |
2244
- | \`virtual-list\` | 30,546 | 10,470 | 9,192 | 2,904 | 1,181 | 649 |
2139
+ | \`accordion\` | 80,416 | 26,550 | 21,816 | 6,258 | 1,975 | 1,399 |
2140
+ | \`announcement\` | 79,088 | 26,034 | 21,464 | 5,042 | 1,489 | 1,099 |
2141
+ | \`app-header\` | 30,683 | 10,087 | 8,885 | 4,489 | 1,317 | 888 |
2142
+ | \`aura\` | 87,842 | 30,863 | 26,680 | 60,879 | 21,466 | 18,593 |
2143
+ | \`avatar\` | 32,433 | 10,538 | 9,281 | 6,205 | 1,781 | 1,278 |
2144
+ | \`badge\` | 29,366 | 9,907 | 8,704 | 3,550 | 1,144 | 814 |
2145
+ | \`bar-chart\` | 87,353 | 27,299 | 24,047 | 28,058 | 7,012 | 5,413 |
2146
+ | \`blockquote\` | 28,015 | 9,529 | 8,383 | 2,077 | 767 | 433 |
2147
+ | \`breadcrumbs\` | 78,416 | 25,590 | 21,198 | 5,334 | 1,454 | 1,153 |
2148
+ | \`button\` | 37,399 | 11,545 | 10,187 | 9,236 | 2,232 | 1,639 |
2149
+ | \`button-group\` | 28,508 | 9,543 | 8,424 | 2,320 | 754 | 446 |
2150
+ | \`callout\` | 76,173 | 25,235 | 20,977 | 2,914 | 1,011 | 742 |
2151
+ | \`card\` | 30,101 | 10,012 | 8,842 | 3,917 | 1,172 | 843 |
2152
+ | \`carousel\` | 89,716 | 28,257 | 23,609 | 16,487 | 3,950 | 3,041 |
2153
+ | \`chat\` | 96,458 | 30,119 | 24,932 | 21,033 | 4,920 | 3,833 |
2154
+ | \`checkbox\` | 40,821 | 12,584 | 11,091 | 8,411 | 2,390 | 1,743 |
2155
+ | \`checkbox-group\` | 39,793 | 12,366 | 10,895 | 6,888 | 2,197 | 1,425 |
2156
+ | \`code\` | 26,546 | 9,065 | 7,981 | 1,529 | 585 | 353 |
2157
+ | \`code-block\` | 126,793 | 40,099 | 33,817 | 25,870 | 5,745 | 4,508 |
2158
+ | \`color-input\` | 162,845 | 47,380 | 40,111 | 57,622 | 11,935 | 10,051 |
2159
+ | \`color-picker\` | 126,684 | 36,608 | 30,439 | 45,772 | 9,885 | 8,284 |
2160
+ | \`combobox\` | 140,948 | 43,524 | 36,682 | 33,925 | 7,923 | 6,293 |
2161
+ | \`command\` | 110,979 | 34,028 | 28,065 | 27,611 | 6,895 | 5,493 |
2162
+ | \`copy-button\` | 122,915 | 39,507 | 33,361 | 21,994 | 5,157 | 3,968 |
2163
+ | \`data-table\` | 171,800 | 49,868 | 42,094 | 65,280 | 14,167 | 11,566 |
2164
+ | \`date-input\` | 138,993 | 43,266 | 36,617 | 34,215 | 8,160 | 6,694 |
2165
+ | \`date-picker\` | 91,241 | 29,416 | 24,327 | 15,402 | 4,304 | 3,406 |
2166
+ | \`dialog\` | 34,819 | 11,243 | 9,909 | 7,037 | 2,150 | 1,594 |
2167
+ | \`divider\` | 29,181 | 9,820 | 8,610 | 3,243 | 1,049 | 722 |
2168
+ | \`donut-chart\` | 79,399 | 25,131 | 22,173 | 21,457 | 5,448 | 4,033 |
2169
+ | \`drawer\` | 33,085 | 10,746 | 9,460 | 5,591 | 1,651 | 1,258 |
2170
+ | \`drilldown\` | 85,015 | 27,777 | 22,820 | 9,404 | 2,708 | 2,034 |
2171
+ | \`empty\` | 28,295 | 9,601 | 8,463 | 2,107 | 798 | 588 |
2172
+ | \`file-input\` | 96,132 | 30,394 | 25,004 | 16,954 | 4,318 | 3,346 |
2173
+ | \`flex\` | 27,799 | 9,392 | 8,240 | 1,986 | 673 | 463 |
2174
+ | \`format-date\` | 30,905 | 10,420 | 9,233 | 3,435 | 1,102 | 726 |
2175
+ | \`grid\` | 28,326 | 9,564 | 8,449 | 2,511 | 843 | 595 |
2176
+ | \`heatmap\` | 72,928 | 24,255 | 21,435 | 14,814 | 4,498 | 3,331 |
2177
+ | \`icon\` | 74,256 | 24,607 | 20,394 | 1,528 | 613 | 284 |
2178
+ | \`icon-button\` | 37,727 | 11,481 | 10,120 | 9,568 | 2,163 | 1,587 |
2179
+ | \`image\` | 30,564 | 10,174 | 8,943 | 4,699 | 1,516 | 1,088 |
2180
+ | \`input\` | 90,860 | 29,217 | 23,927 | 10,895 | 2,997 | 2,248 |
2181
+ | \`kbd\` | 30,118 | 10,382 | 9,139 | 4,294 | 1,762 | 1,231 |
2182
+ | \`legend\` | 34,022 | 11,148 | 9,812 | 5,924 | 1,710 | 1,182 |
2183
+ | \`line-chart\` | 82,192 | 26,074 | 23,014 | 22,899 | 5,824 | 4,292 |
2184
+ | \`list\` | 31,940 | 10,292 | 9,050 | 5,770 | 1,512 | 1,226 |
2185
+ | \`listbox\` | 96,658 | 31,152 | 25,519 | 14,779 | 4,354 | 3,220 |
2186
+ | \`loader\` | 30,078 | 10,033 | 8,830 | 3,891 | 1,161 | 878 |
2187
+ | \`megamenu\` | 60,316 | 20,594 | 18,232 | 9,342 | 2,771 | 2,053 |
2188
+ | \`menu\` | 116,491 | 38,410 | 32,480 | 14,285 | 3,708 | 2,802 |
2189
+ | \`meter\` | 35,367 | 11,232 | 9,921 | 9,185 | 2,414 | 1,935 |
2190
+ | \`navigation\` | 30,214 | 10,212 | 8,987 | 2,949 | 1,064 | 655 |
2191
+ | \`notifications\` | 92,415 | 29,580 | 24,433 | 16,186 | 4,091 | 3,171 |
2192
+ | \`number-input\` | 91,816 | 29,585 | 24,291 | 11,928 | 3,385 | 2,491 |
2193
+ | \`option\` | 32,116 | 10,548 | 9,315 | 5,935 | 1,760 | 1,226 |
2194
+ | \`outline\` | 35,566 | 11,583 | 10,246 | 8,251 | 2,550 | 1,778 |
2195
+ | \`pagination\` | 149,985 | 45,089 | 38,045 | 43,666 | 9,526 | 7,717 |
2196
+ | \`pin-input\` | 40,676 | 12,803 | 11,279 | 8,259 | 2,654 | 2,002 |
2197
+ | \`popover\` | 55,826 | 19,462 | 17,235 | 4,603 | 1,489 | 1,046 |
2198
+ | \`progress\` | 33,160 | 10,749 | 9,508 | 6,978 | 1,946 | 1,517 |
2199
+ | \`qr-code\` | 40,238 | 13,974 | 12,313 | 14,441 | 5,376 | 4,396 |
2200
+ | \`quote\` | 27,030 | 9,207 | 8,088 | 1,211 | 543 | 230 |
2201
+ | \`radio\` | 43,516 | 12,844 | 11,308 | 10,669 | 2,572 | 1,892 |
2202
+ | \`rating\` | 41,008 | 13,169 | 11,612 | 8,574 | 2,932 | 2,109 |
2203
+ | \`sandbox\` | 60,999 | 16,779 | 14,889 | 34,537 | 8,005 | 6,566 |
2204
+ | \`scroll-area\` | 31,431 | 10,376 | 9,102 | 5,561 | 1,744 | 1,128 |
2205
+ | \`select\` | 133,744 | 42,058 | 35,488 | 27,551 | 6,632 | 5,215 |
2206
+ | \`skeleton\` | 28,062 | 9,544 | 8,416 | 2,242 | 832 | 568 |
2207
+ | \`slider\` | 47,778 | 13,857 | 12,277 | 15,115 | 3,569 | 2,799 |
2208
+ | \`sparkline\` | 35,412 | 12,015 | 10,603 | 6,285 | 2,003 | 1,558 |
2209
+ | \`speed-dial\` | 110,306 | 36,504 | 30,886 | 11,251 | 2,716 | 1,971 |
2210
+ | \`splitter\` | 42,441 | 12,678 | 11,269 | 16,259 | 3,939 | 3,134 |
2211
+ | \`stat\` | 29,954 | 9,789 | 8,646 | 3,774 | 1,011 | 725 |
2212
+ | \`steps\` | 96,252 | 29,575 | 24,410 | 19,643 | 4,204 | 3,348 |
2213
+ | \`switch\` | 38,603 | 12,160 | 10,668 | 6,072 | 1,895 | 1,306 |
2214
+ | \`table\` | 35,190 | 10,865 | 9,580 | 7,692 | 1,917 | 1,426 |
2215
+ | \`tabs\` | 40,196 | 12,332 | 10,861 | 10,719 | 2,594 | 1,939 |
2216
+ | \`tag\` | 77,633 | 25,634 | 21,148 | 4,076 | 1,244 | 880 |
2217
+ | \`text\` | 29,734 | 9,670 | 8,508 | 3,922 | 967 | 650 |
2218
+ | \`textarea\` | 40,350 | 12,544 | 11,034 | 7,447 | 2,228 | 1,644 |
2219
+ | \`time-input\` | 156,103 | 46,933 | 39,629 | 48,526 | 11,002 | 8,949 |
2220
+ | \`time-picker\` | 111,867 | 34,716 | 28,718 | 29,452 | 7,605 | 6,027 |
2221
+ | \`timeline\` | 78,237 | 25,530 | 21,180 | 5,151 | 1,366 | 981 |
2222
+ | \`toast\` | 85,449 | 27,484 | 22,691 | 11,274 | 2,870 | 2,137 |
2223
+ | \`toggle\` | 43,243 | 13,254 | 11,675 | 8,954 | 2,503 | 1,844 |
2224
+ | \`toolbar\` | 29,632 | 10,054 | 8,841 | 3,813 | 1,475 | 913 |
2225
+ | \`tooltip\` | 60,498 | 20,576 | 18,184 | 9,763 | 2,945 | 2,103 |
2226
+ | \`tour\` | 71,822 | 22,543 | 19,985 | 20,127 | 4,599 | 3,480 |
2227
+ | \`tree\` | 89,446 | 29,019 | 23,862 | 12,065 | 3,544 | 2,650 |
2228
+ | \`trend\` | 76,798 | 25,221 | 20,884 | 4,083 | 1,172 | 831 |
2229
+ | \`video\` | 150,914 | 45,855 | 38,950 | 48,454 | 10,824 | 9,072 |
2230
+ | \`video-playlist\` | 130,351 | 40,960 | 34,695 | 26,741 | 5,898 | 4,740 |
2231
+ | \`virtual-list\` | 30,546 | 10,470 | 9,192 | 2,904 | 1,153 | 858 |
2245
2232
 
2246
2233
  ## What lands in \`node_modules\`
2247
2234
 
@@ -2253,12 +2240,12 @@ column is what was removed rather than part of what remains.
2253
2240
 
2254
2241
  | Package | Unpacked | Files | Source maps stripped | Runtime dependencies |
2255
2242
  |---|---|---|---|---|
2256
- | \`@fusion.dev/helix-core\` | 910,682 | 113 | 160,137 | \`@floating-ui/dom\`, \`@fusion.dev/helix-icons\` |
2257
- | \`@fusion.dev/helix-headless\` | 10,110,995 | 422 | 737,978 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-icons\`, \`uqr\` |
2258
- | \`@fusion.dev/helix-icons\` | 65,119 | 11 | 20,405 | none |
2259
- | \`@fusion.dev/helix-styles\` | 83,183 | 5 | 0 | none |
2260
- | \`@fusion.dev/helix-theme\` | 465,772 | 8 | 4,793 | none |
2261
- | \`@fusion.dev/helix\` | 10,029,875 | 717 | 287,558 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-headless\`, \`@fusion.dev/helix-styles\` |
2243
+ | \`@fusion.dev/helix-core\` | 875,831 | 113 | 161,883 | \`@floating-ui/dom\`, \`@fusion.dev/helix-icons\` |
2244
+ | \`@fusion.dev/helix-headless\` | 9,741,797 | 422 | 738,193 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-icons\`, \`uqr\` |
2245
+ | \`@fusion.dev/helix-icons\` | 66,379 | 11 | 20,959 | none |
2246
+ | \`@fusion.dev/helix-styles\` | 83,277 | 5 | 0 | none |
2247
+ | \`@fusion.dev/helix-theme\` | 463,476 | 8 | 4,764 | none |
2248
+ | \`@fusion.dev/helix\` | 9,714,436 | 718 | 287,181 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-headless\`, \`@fusion.dev/helix-styles\` |
2262
2249
 
2263
2250
  ## Not measured yet
2264
2251
 
@@ -2266,8 +2253,8 @@ Named rather than left out, because a metrics page is read for what it does
2266
2253
  not say as much as for what it does.
2267
2254
 
2268
2255
  - **No whole-library comparison, and no fifth component.** The comparison above is five components against four systems. Widening it means naming the equivalent element in each system by hand, which is where a comparison table starts arguing, so each addition is a deliberate one rather than a sweep.
2269
- - **The peer numbers are pinned, so they age.** They are dated in the section above and refreshed by running \`bun run metrics:peers\`. Nothing fails when they are old, because nothing in this repository changes when somebody else releases, and a check that fired on the calendar would be noise.
2270
- - **No load or rendering timings.** First paint, time to upgrade, and the cost of hydrating a server-rendered tree. These need a browser harness rather than a bundler, and they never join a cross-system table.
2256
+ - **The peer numbers are pinned, so they age.** They are dated in the section above and refreshed by running \`turbo run peers\`. Nothing fails when they are old, because nothing in this repository changes when somebody else releases, and a check that fired on the calendar would be noise.
2257
+ - **No first paint.** The timings above are facts about a component: time to upgrade, first render, hydration. First paint is a fact about a whole page, so it belongs to whatever renders one rather than to the library it renders.
2271
2258
  - **No per-component stylesheet bytes.** There are none to report: a family's CSS is compiled into its JavaScript, so it is already inside every number above. \`elements.css\` is the light-DOM layer and is in the stylesheet table.
2272
2259
  `,
2273
2260
  motion: `---
@@ -2396,17 +2383,18 @@ should end up passing that string through.
2396
2383
  element.addEventListener('helix-before-change', (event) => console.log(event.detail))
2397
2384
  \`\`\`
2398
2385
 
2399
- **A declared \`value\`, \`open\`, \`checked\` or \`active\` is a claim of ownership.**
2400
- The element announces the change and applies none of it, and waits to be told.
2401
- Use \`default-value\`, \`default-open\` and their siblings for a control that owns
2402
- its own state. This is the rule most likely to look like a bug, and
2386
+ **A declared \`value\`, \`open\`, \`checked\` or \`active\` is a seed.** The element
2387
+ starts there and goes on managing itself, exactly as \`<input value="Ada">\` does.
2388
+ To take one decision, listen for the matching \`helix-before-*\` event and call
2389
+ \`preventDefault()\`; to own the state outright, refuse and assign your own.
2390
+ \`default-value\`, \`default-open\` and their siblings are what a reset returns to.
2403
2391
  [State and control](./state-and-control) is the page about it.
2404
2392
 
2405
2393
  ## What each one needs
2406
2394
 
2407
2395
  | Framework | Notes |
2408
2396
  |---|---|
2409
- | Solid | Sets properties on custom elements by default. Use \`prop:\` to force one and \`attr:\` to force the other. \`on:helix-change\` binds the literal name |
2397
+ | Solid | Sets properties on custom elements by default. Use \`prop:\` to force one and \`attr:\` to force the other. \`on:helix-before-change\` binds the literal name |
2410
2398
  | Qwik | Works as JSX. Bind with \`document:on…\` or a ref, since a plain \`on*\` prop is normalized |
2411
2399
  | Lit | \`.prop=\`, \`?bool=\` and \`@helix-before-change=\` are already the right three channels |
2412
2400
  | Ember | Angle-bracket invocation passes attributes only, so set properties from a modifier |
@@ -2555,12 +2543,14 @@ Three doors are open, and they are in the order you should try them.
2555
2543
 
2556
2544
  \`\`\`css
2557
2545
  :root {
2558
- --helix-radii-md: 2px;
2546
+ --helix-seed-radii: 2px;
2559
2547
  }
2560
2548
  \`\`\`
2561
2549
 
2562
2550
  If every card, dialog and button should be squarer, that is a token change and
2563
- you are done. Tokens cross shadow boundaries on their own, because custom
2551
+ you are done. The seed rather than \`--helix-radii-md\`, because the four rungs
2552
+ are derived from it: \`md\` on its own is one step of four, and the buttons and
2553
+ dialogs are on a different one. See [Shape and borders](./shape-and-borders). Tokens cross shadow boundaries on their own, because custom
2564
2554
  properties inherit, so one declaration reaches every component at once.
2565
2555
 
2566
2556
  Reach for this first. Most requests that arrive as "can I restyle the button"
@@ -2589,10 +2579,7 @@ changes that component and nothing else.
2589
2579
  after the component (\`--card-padding\`, \`--drawer-radius\`) and a token is named
2590
2580
  \`--helix-*\`. Every documented hook is held to a rule that actually reads it, in
2591
2581
  both directions: declared and never read is a promise with nothing behind it,
2592
- and read and never declared is a working feature nobody is told about. Three of
2593
- \`Button\`'s four hooks were inert for a refactor's worth of time while the
2594
- reference went on listing them, which is how that check came
2595
- to exist.
2582
+ and read and never declared is a working feature nobody is told about.
2596
2583
 
2597
2584
  Each component's page lists its hooks under Custom properties.
2598
2585
 
@@ -2615,10 +2602,8 @@ internal structure.
2615
2602
 
2616
2603
  **A published part is a promise**, held both ways:
2617
2604
  a documented part that nothing renders, and a rendered part nobody was told
2618
- about. The second is the worse of the two, because a \`::part()\` that resolves to
2619
- nothing is valid CSS that matches nothing and reports nothing. \`Breadcrumbs\`
2620
- published a \`nav\` part the family does not render; \`Checkbox\` renders the
2621
- \`field\` part the whole styled appearance is built on and never declared it.
2605
+ about. The first is the worse of the two for you, because a \`::part()\` that
2606
+ resolves to nothing is valid CSS that matches nothing and reports nothing.
2622
2607
 
2623
2608
  Each component's page lists its parts.
2624
2609
 
@@ -2643,12 +2628,11 @@ its arrow is \`tooltip-arrow\`.
2643
2628
  \`Command\` forwarded the listbox's \`search-field\` under a name it also rendered
2644
2629
  itself, so \`::part(search-field)\` matched two elements at once.
2645
2630
 
2646
- This is checked in both directions. \`check:parts\` holds a published part and a
2647
- rendered one to each other, and \`check:exportparts\` holds a composition to
2631
+ This is checked in both directions. \`helix component\`'s \`parts\` holds a published part and a
2632
+ rendered one to each other, and \`helix component\`'s \`exportparts\` holds a composition to
2648
2633
  forwarding everything its child publishes, under one prefix, colliding with
2649
- nothing. Before it existed, 148 published child parts were unreachable: all
2650
- sixteen of the color picker's from inside a color input, all thirteen of the
2651
- date picker's from inside a date input.
2634
+ nothing. So every part the color picker publishes is reachable from inside a
2635
+ color input, and every part the date picker publishes from inside a date input.
2652
2636
 
2653
2637
  If you still find a part you cannot reach, that is worth reporting rather than
2654
2638
  working around: the missing part is the bug.
@@ -3010,9 +2994,9 @@ amount of JavaScript reproduces:
3010
2994
  - right-click offers Copy Link Address
3011
2995
  - a crawler follows it
3012
2996
 
3013
- Before \`href\` existed, the docs sidebar put a \`<Link>\` inside each row. The
3014
- anchor was 57px of a 240px row, so five sixths of every row did nothing, and
3015
- Enter did nothing at all: the tree announced a selection and no anchor heard it.
2997
+ A \`<Link>\` inside each row buys none of it. In the docs sidebar the anchor was
2998
+ 57px of a 240px row, so five sixths of every row did nothing, and Enter did
2999
+ nothing at all: the tree announced a selection and no anchor heard it.
3016
3000
 
3017
3001
  ## \`href\` and a framework's \`<Link>\`
3018
3002
 
@@ -3171,7 +3155,7 @@ host is the only element the listbox can point at.
3171
3155
  same browser, the accessibility tree for \`<div role="option"><a href>Open
3172
3156
  settings</a></div>\` inside a listbox is an option with *no accessible name*, and
3173
3157
  the link exposed as a child of it. The sibling option with plain text is named
3174
- correctly. So the manoeuvre that works for \`treeitem\` and \`menuitem\`, moving the
3158
+ correctly. So the maneuver that works for \`treeitem\` and \`menuitem\`, moving the
3175
3159
  role onto the anchor, is exactly the one thing that cannot be done here.
3176
3160
 
3177
3161
  Two constraints pointing opposite ways, and no arrangement satisfies both.
@@ -3301,7 +3285,7 @@ has a tree.
3301
3285
  **Anything that inspects the tree runs in \`firstUpdated\` or later**, and is
3302
3286
  therefore a client-side enhancement by definition.
3303
3287
 
3304
- ## Never initialise state in \`connectedCallback\`
3288
+ ## Never initialize state in \`connectedCallback\`
3305
3289
 
3306
3290
  SSR does not call it. Derive from properties, or seed in \`willUpdate\`, which SSR
3307
3291
  does call.
@@ -3391,18 +3375,30 @@ square: a percentage radius on a wide element gives an ellipse, and a pill is
3391
3375
  what you wanted.
3392
3376
 
3393
3377
  Rounding is the fastest single change to how a system feels, and it is one
3394
- token:
3378
+ token, but it is the **seed** rather than one of the four above:
3395
3379
 
3396
3380
  \`\`\`css
3397
3381
  :root {
3398
- --helix-radii-md: 2px;
3382
+ --helix-seed-radii: 2px;
3399
3383
  }
3400
3384
  \`\`\`
3401
3385
 
3402
- That makes every card, dialog, input and button squarer at once. The theme
3386
+ That makes every card, dialog, input and button squarer at once, because \`sm\`,
3387
+ \`md\` and \`lg\` are all derived from it: they become 1px, 2px and 3px. The theme
3403
3388
  engine takes a \`radius\` intent input for exactly this reason. See [Deriving a
3404
3389
  theme](./theming).
3405
3390
 
3391
+ **Setting \`--helix-radii-md\` instead moves only what reads \`md\`**, which is
3392
+ neither the buttons, the inputs and the dialogs (\`sm\`) nor the cards (\`lg\`).
3393
+ The four rungs are siblings derived from the seed, not a chain, so overriding
3394
+ one is how you change a single step on purpose rather than how you reshape a
3395
+ system.
3396
+
3397
+ **Every floating panel takes \`sm\`.** A dialog, a drawer, a menu, a popover, a
3398
+ tooltip, a toast, and the panel any field opens under itself: all the same
3399
+ corner, whatever the panel's size. A radius is read against the corner beside it
3400
+ rather than against the area behind it.
3401
+
3406
3402
  **A shape that is round rather than softened does not use these.** An avatar, a
3407
3403
  loader and a radio are circles because of what they are, so they say \`50%\`
3408
3404
  directly and are unaffected by a theme that squares everything else off.
@@ -3425,11 +3421,10 @@ belong to [Surfaces and separation](./surfaces-and-separation): they are what a
3425
3421
  theme sets to zero to go shadow-first, or to a width to go border-first.
3426
3422
 
3427
3423
  This distinction is why a component's border width sits behind a per-component
3428
- hook rather than being written inline. Of 68 border declarations reaching for
3429
- \`--helix-color-border\` before this was fixed, eight put the *color* behind a
3430
- hook and none put the width behind one, so a border could be recoloured and
3431
- never removed, and the floating surfaces wrote \`border: none\` outright so one
3432
- could never be added either.
3424
+ hook rather than being written inline. A width written inline can be recolored
3425
+ by a theme and never removed, and a hardcoded \`border: none\` can never have one
3426
+ added back, so a surface themes perfectly in one direction and not at all in the
3427
+ other.
3433
3428
 
3434
3429
  ## Corner radius on a group
3435
3430
 
@@ -3583,7 +3578,7 @@ Use them for gap, padding and margin:
3583
3578
 
3584
3579
  ## Size
3585
3580
 
3586
- Thirty-four tokens, and almost all of them name a specific thing:
3581
+ Forty-one tokens, and almost all of them name a specific thing:
3587
3582
  \`--helix-size-control\`, \`--helix-size-checkbox\`, \`--helix-size-switch\`,
3588
3583
  \`--helix-size-avatar\`, \`--helix-size-icon\`, \`--helix-size-tag\`,
3589
3584
  \`--helix-size-header\`, \`--helix-size-progress\`, \`--helix-size-meter\`.
@@ -3645,11 +3640,11 @@ That works. Type in it and the value moves. Assign to it later and the value
3645
3640
  moves to what you assigned. There is no mode to be in and nothing to wire before
3646
3641
  the control responds.
3647
3642
 
3648
- *This page said the opposite until 26 Aug 2026, and the sample above was printed
3649
- as plain text with an instruction not to paste it. Writing a property was a
3650
- claim of ownership, so the element announced its changes and applied none of
3651
- them until it was told, and that markup produced a field that ignored every
3652
- keystroke with nothing logged and nothing visibly wrong.*
3643
+ *This page said the opposite until 26 Aug 2026: writing a property was a claim
3644
+ of ownership, so the element announced its changes and applied none of them
3645
+ until it was told. The mode is deleted. If you were refusing a change by
3646
+ withholding a state update rather than by calling \`preventDefault()\`, that is
3647
+ the one thing that has to be rewritten.*
3653
3648
 
3654
3649
  ## Taking a decision
3655
3650
 
@@ -3896,9 +3891,9 @@ because Svelte was already right about custom elements.
3896
3891
  \`bind:\` does not work on a Helix control, because there is no two-way binding
3897
3892
  convention a custom element can opt into. Read the value off the event.
3898
3893
 
3899
- And a declared \`value\`, \`open\`, \`checked\` or \`active\` is a claim of ownership:
3900
- the element announces and waits rather than applying the change itself. Use
3901
- \`default-value\` and its siblings when you want the element to own its own state.
3894
+ And a declared \`value\`, \`open\`, \`checked\` or \`active\` is a seed: the element
3895
+ starts there and goes on applying its own changes. To refuse one, cancel the
3896
+ matching \`helix-before-*\` event; withholding a state update refuses nothing.
3902
3897
  See [State and control](./state-and-control).
3903
3898
  `,
3904
3899
  'theme-builder': `---
@@ -3958,7 +3953,7 @@ export const theme = { brand: '#2563eb', chroma: { ceiling: 0.1 }, radius: 2 }
3958
3953
 
3959
3954
  **Keep the intent, not the tokens.** The tokens are the output of a solver, and
3960
3955
  the solver improves: a theme stored as its inputs picks up a better derivation,
3961
- and a theme stored as 176 literal values is frozen at the version that produced
3956
+ and a theme stored as literal values is frozen at the version that produced
3962
3957
  it. The tokens are for pasting into a system that cannot run the engine.
3963
3958
 
3964
3959
  ## What it does not do
@@ -4033,7 +4028,7 @@ console.log(toCss(theme))
4033
4028
  \`\`\`
4034
4029
 
4035
4030
  The emitted block carries the seeds as well as the tokens, so the halves the
4036
- engine does not compute, the twenty-four series colours a chart reads, the
4031
+ engine does not compute, the twenty-four series colors a chart reads, the
4037
4032
  spacing scale and the corner radii, re-derive from the same values the solver
4038
4033
  used. That is what stops the two paths disagreeing on the same page.
4039
4034
 
@@ -4097,7 +4092,7 @@ direction never reverses.
4097
4092
  | \`@fusion.dev/helix-styles\` | Tokens and the base layer. Pure CSS | nothing |
4098
4093
  | \`@fusion.dev/helix-core\` | Element base class, mixins, decorators | Lit |
4099
4094
  | \`@fusion.dev/helix-headless\` | Structure, accessibility, state, form participation | \`core\` |
4100
- | \`@fusion.dev/helix\` | Presentation: tokens, parts, and the visual axes | \`headless\`, \`styles\` |
4095
+ | \`@fusion.dev/helix\` | Presentation: tokens, parts, and the visual axes | \`headless\`, \`turbo run styles\` |
4101
4096
 
4102
4097
  \`@fusion.dev/helix-theme\` and \`@fusion.dev/helix-icons\` ship beside the stack rather than in it:
4103
4098
  neither is a tier, and neither is needed to render a component. **There is no
@@ -4107,7 +4102,7 @@ the bridge that repairs React's hydration of custom events is in
4107
4102
 
4108
4103
  ## Why the split
4109
4104
 
4110
- **\`headless\` must never depend on \`styles\`.**
4105
+ **\`headless\` must never depend on \`turbo run styles\`.**
4111
4106
 
4112
4107
  That single constraint is what makes the headless tier independently
4113
4108
  consumable. Consume it and bring your own
@@ -4284,10 +4279,10 @@ be lifted into: a raised surface goes *down* the ramp, not up.
4284
4279
  groove.
4285
4280
 
4286
4281
  **\`raised\` and \`overlay\` are the pair worth learning.** They land on the same
4287
- step in dark mode, which is why one token tried to do both jobs for a while. In
4288
- light they want opposite fills: a hovered row must be darker than a white page,
4289
- and a thumb must be lighter than the groove it sits in. If something looks
4290
- almost right in dark and wrong in light, this is usually why.
4282
+ step in dark mode, so one token looks like it would do both jobs. In light they
4283
+ want opposite fills: a hovered row must be darker than a white page, and a thumb
4284
+ must be lighter than the groove it sits in. If something looks almost right in
4285
+ dark and wrong in light, this is usually why.
4291
4286
 
4292
4287
  ## Per-component hooks
4293
4288
 
@@ -4497,37 +4492,37 @@ request and names every document plus these two surfaces.
4497
4492
 
4498
4493
  These are in order of how often they look like a library bug and are not.
4499
4494
 
4500
- ### 1. A declared \`value\` hands you the control
4501
-
4502
- \`\`\`text
4503
- <!-- Ignores every keystroke. Nothing is logged. Nothing looks wrong. -->
4504
- <helix-input label="Name" value="Ada"></helix-input>
4505
- \`\`\`
4495
+ ### 1. Refusing a change by not answering
4506
4496
 
4507
- Do not paste it. Plain text rather than a live example, the same way
4508
- [State and control](./state-and-control) shows this one: a reader copies what is
4509
- in front of them, and these are the two pages that have to show the mistake in
4510
- order to name it.
4511
-
4512
- **Writing \`value\`, \`open\`, \`checked\` or \`active\` is a claim of ownership.** From
4513
- then on the element announces changes and applies none of them, waiting to be
4514
- told. Which mode it is in is read once, at its first update.
4515
-
4516
- Seed with the \`default-\` twin, or answer the event:
4497
+ **Writing \`value\`, \`open\`, \`checked\` or \`active\` is a seed and a correction.**
4498
+ The element starts there and goes on applying its own changes, exactly as
4499
+ \`<input value="Ada">\` does, so this works and needs no handler beside it:
4517
4500
 
4518
4501
  \`\`\`html
4519
4502
  <helix-input
4520
- default-value="Ada"
4521
4503
  label="Name"
4504
+ value="Ada"
4522
4505
  ></helix-input>
4523
4506
  \`\`\`
4524
4507
 
4508
+ The trap is on the other side. React force-restores a native \`<input>\` whose
4509
+ state did not move and does not do this for a custom element, so a handler that
4510
+ declines to call \`setState\` leaves the element holding the new value. Refusal is
4511
+ \`preventDefault()\` on the matching \`helix-before-*\` event:
4512
+
4525
4513
  \`\`\`tsx
4526
- <helix-input label="Name" onChange={(e) => setName(e.currentTarget.value)} value={name} />
4514
+ <helix-input
4515
+ label="Name"
4516
+ onhelix-before-change={(event) => {
4517
+ event.preventDefault()
4518
+ setName(clean(event.detail.value))
4519
+ }}
4520
+ value={name}
4521
+ />
4527
4522
  \`\`\`
4528
4523
 
4529
- In TypeScript this is a compile error rather than a surprise. Everywhere else the
4530
- element warns on its second unanswered request.
4524
+ \`default-value\` and its twins are what a reset returns to. See
4525
+ [State and control](./state-and-control).
4531
4526
 
4532
4527
  ### 2. The event name is the event's own
4533
4528
 
@@ -4569,10 +4564,11 @@ The tell for a missing layer is which. A flash before hydration is
4569
4564
  \`elements.css\`; bare headings are \`base.css\`. **No color anywhere means the
4570
4565
  ramp or the semantic layer, and the two are told apart by what is in the
4571
4566
  stylesheet rather than by what is on screen**: without \`tokens.css\` nothing
4572
- declares \`--helix-color-*\` at all, while without \`primitives.css\` all 177 are
4573
- declared and every one resolves to \`rgba(0, 0, 0, 0)\`, since \`tokens.css\` refers
4574
- to a primitive 235 times and to nothing else. The second is the one that looks
4575
- like a working install, and it is the reason \`all.css\` exists.
4567
+ declares \`--helix-color-*\` at all, while without \`primitives.css\` all 185
4568
+ semantic tokens are declared and every color resolves to \`rgba(0, 0, 0, 0)\`,
4569
+ since \`tokens.css\` refers to a primitive 297 times and to nothing else. The
4570
+ second is the one that looks like a working install, and it is the reason
4571
+ \`all.css\` exists.
4576
4572
 
4577
4573
  ## Choosing a family
4578
4574
 
@@ -4594,9 +4590,11 @@ Two distinctions worth knowing before searching:
4594
4590
 
4595
4591
  Three doors, in the order to try them.
4596
4592
 
4597
- 1. **A token.** \`--helix-radii-md: 2px\` at \`:root\` reaches every component,
4593
+ 1. **A token.** \`--helix-seed-radii: 2px\` at \`:root\` reaches every component,
4598
4594
  because custom properties inherit. Most "can I restyle the button" is really
4599
- "our brand has less rounding".
4595
+ "our brand has less rounding". The seed and not \`--helix-radii-md\`: the four
4596
+ radii are siblings derived from it, so \`md\` alone moves neither the buttons
4597
+ nor the cards.
4600
4598
  2. **A per-component hook.** \`--card-padding\` on \`helix-card\`. Named after the
4601
4599
  component, documented on its page, defaults to a semantic token.
4602
4600
  3. **A part.** \`helix-select::part(trigger)\`. The most powerful and the one that
@@ -4638,7 +4636,7 @@ for the API.
4638
4636
 
4639
4637
  | Tool | Where it goes |
4640
4638
  |---|---|
4641
- | Claude Code | \`CLAUDE.md\`, or a skill in \`.claude/skills/\` |
4639
+ | Claude Code | \`AGENTS.md\` or \`CLAUDE.md\`, or a skill in \`.claude/skills/\` |
4642
4640
  | Cursor | \`.cursor/rules/\` |
4643
4641
  | GitHub Copilot | \`.github/copilot-instructions.md\` |
4644
4642
  | Anything else | Whatever it reads. The line is the same |
@@ -4744,8 +4742,6 @@ inspecting it.
4744
4742
  - \`onHelixOpen\` binds an event called \`HelixOpen\`, which nobody dispatches. ❌
4745
4743
 
4746
4744
  The number of hyphens does not matter, measured in Chrome against React 19.2.8.
4747
- An earlier version of this page said two were a hard stop; that was the
4748
- hydration bug above, read as a fact about names.
4749
4745
 
4750
4746
  ## Register once, in a client component
4751
4747
 
@@ -4909,8 +4905,7 @@ vocabularies. You cannot invent a value, and a component may take a subset.
4909
4905
  ## Why two axes
4910
4906
 
4911
4907
  **The library had four axes and one word for all of them.** Counted across both
4912
- tiers, \`appearance\` held 21 declarations describing at least four different
4913
- questions: where a surface ends (\`outlined\` against \`plain\` on a Card), how much
4908
+ tiers, \`appearance\` described at least four different questions: where a surface ends (\`outlined\` against \`plain\` on a Card), how much
4914
4909
  ink a control claims (\`ghost\` against \`solid\` on a Button), which widget gets
4915
4910
  rendered (\`segmented\` against \`underlined\` on Tabs), and in one case a plain
4916
4911
  misfiled tone.
@@ -4925,10 +4920,9 @@ and a component reintroducing it fails the build.
4925
4920
 
4926
4921
  ## Two axes, not one
4927
4922
 
4928
- This is the test, and the library found it before the registry existed.
4929
- \`megamenu-root.css\` reads: a consumer can make the panel glass, which is not an
4930
- appearance, because \`full\` already occupies that axis with a layout. A panel can
4931
- be glass *and* outlined. Two axes.
4923
+ This is the test. \`Megamenu\` is the worked example: a consumer can make the panel
4924
+ glass, which is not an appearance, because \`full\` already occupies that axis with
4925
+ a layout. A panel can be glass *and* outlined. Two axes.
4932
4926
 
4933
4927
  If you are adding a property and cannot decide which axis it belongs to, that is
4934
4928
  usually the answer: it is two properties.
@@ -4946,7 +4940,7 @@ choice between two widgets, which is structural wherever it is made, so it lives
4946
4940
  on either tier.
4947
4941
 
4948
4942
  **What it may not be is a place to put something that is on an axis.** That is
4949
- the failure mode \`appearance\` demonstrated for 21 components.
4943
+ the failure mode \`appearance\` demonstrated.
4950
4944
 
4951
4945
  ## \`tone\` is the one axis both tiers carry
4952
4946
 
@@ -5144,11 +5138,10 @@ against the stylesheet's own URL with no bundler involved. Copy the whole
5144
5138
  four requests and both layers resolve.
5145
5139
 
5146
5140
  *This page listed \`tokens.css\` and \`base.css\` and no \`primitives.css\` until 24
5147
- Aug 2026, which is the same omission \`installation.mdx\`, \`introduction.mdx\` and
5148
- the agent page carried. \`tokens.css\` refers to a primitive 235 times and imports
5149
- nothing, so a reader who followed this got all 178 semantic tokens declared and
5150
- every one resolving to \`rgba(0, 0, 0, 0)\`. Linking \`all.css\` is the fix that
5151
- cannot be got wrong again.*
5141
+ Aug 2026. \`tokens.css\` refers to a primitive 297 times and imports nothing, so a
5142
+ reader who followed that got all 185 semantic tokens declared and every color
5143
+ resolving to \`rgba(0, 0, 0, 0)\`. If your page looks unstyled in exactly that
5144
+ way, link \`all.css\` instead.*
5152
5145
 
5153
5146
  \`elements.css\` stays its own link, being \`@fusion.dev/helix\`'s rather than this
5154
5147
  package's, and it matters more here than anywhere: with no bundler the module