@fusion.dev/helix-docs 0.104.1 → 0.105.0

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 (48) hide show
  1. package/content/accessibility.mdx +92 -71
  2. package/content/angular.mdx +26 -24
  3. package/content/browser-support.mdx +61 -58
  4. package/content/building-on-the-headless-tier.mdx +100 -74
  5. package/content/charting.mdx +98 -79
  6. package/content/coding-agents.mdx +87 -69
  7. package/content/color-modes.mdx +40 -37
  8. package/content/color.mdx +67 -54
  9. package/content/composition.mdx +85 -83
  10. package/content/elevation-and-material.mdx +32 -29
  11. package/content/events.mdx +77 -65
  12. package/content/forms.mdx +69 -58
  13. package/content/iconography.mdx +75 -71
  14. package/content/installation.mdx +77 -68
  15. package/content/intent-reference.mdx +59 -54
  16. package/content/introduction.mdx +25 -23
  17. package/content/localization.mdx +122 -82
  18. package/content/maps.mdx +222 -0
  19. package/content/metrics.mdx +294 -297
  20. package/content/motion.mdx +44 -36
  21. package/content/other-frameworks.mdx +33 -31
  22. package/content/overlays.mdx +72 -54
  23. package/content/overriding-a-component.mdx +85 -74
  24. package/content/react.mdx +72 -64
  25. package/content/recipes.mdx +64 -47
  26. package/content/routing.mdx +100 -93
  27. package/content/sandbox.mdx +39 -39
  28. package/content/server-rendering.mdx +95 -84
  29. package/content/shape-and-borders.mdx +44 -37
  30. package/content/size-and-density.mdx +51 -46
  31. package/content/space-and-size.mdx +41 -34
  32. package/content/state-and-control.mdx +63 -51
  33. package/content/surfaces-and-separation.mdx +55 -53
  34. package/content/svelte.mdx +20 -19
  35. package/content/theme-builder.mdx +42 -31
  36. package/content/theming.mdx +58 -51
  37. package/content/tiers.mdx +69 -61
  38. package/content/tokens.mdx +72 -53
  39. package/content/typography.mdx +47 -47
  40. package/content/using-helix-with-an-agent.mdx +147 -115
  41. package/content/using-the-elements.mdx +55 -50
  42. package/content/versioning.mdx +42 -35
  43. package/content/visual-axes.mdx +168 -146
  44. package/content/vue.mdx +24 -24
  45. package/content/without-a-bundler.mdx +40 -23
  46. package/dist/pages.generated.js +49 -43
  47. package/dist/sources.generated.js +3337 -2680
  48. package/package.json +3 -3
@@ -1,24 +1,32 @@
1
1
  ---
2
- description: Using the headless tier as the foundation for a design system of your own.
2
+ description: Build your own design system on the Helix headless tier, with your own tag names and styles.
3
3
  section: Essentials
4
4
  title: Building on the headless tier
5
5
  ---
6
6
 
7
7
  # Building on the headless tier
8
8
 
9
- The headless tier is a set of components with no stylesheet: structure, ARIA,
10
- keyboard behavior, state and form participation, and nothing about how any of it
11
- looks. That makes it usable as a foundation rather than as a library you consume
12
- whole. Your tags, your stylesheets, our accessibility.
9
+ The headless tier is a set of components with no stylesheet. Each component
10
+ provides:
13
11
 
14
- This is a different thing from theming Helix. Theming keeps our components and
15
- changes their tokens. This keeps our behavior and replaces the presentation
16
- layer outright, under names of your own.
12
+ - structure
13
+ - ARIA
14
+ - keyboard behavior
15
+ - state
16
+ - form participation
17
17
 
18
- ## One line does it
18
+ None of it sets how the component looks. You can use the headless tier as the
19
+ foundation of your own design system, with your own tag names and your own
20
+ stylesheets.
19
21
 
20
- Every headless component renders its children by interpolating a tag rather than
21
- naming one, and the prefix comes from a static on the class:
22
+ Theming Helix keeps our components and changes their tokens. Building on the
23
+ headless tier keeps our behavior and replaces the whole presentation layer,
24
+ under names of your own.
25
+
26
+ ## Set your own tag prefix
27
+
28
+ Every headless component renders its children with an interpolated tag name.
29
+ The prefix of that name comes from a static on the class:
22
30
 
23
31
  ```ts
24
32
  import { HelixHeadlessCombobox } from '@fusion.dev/helix-headless/combobox'
@@ -30,19 +38,18 @@ export class AcmeCombobox extends HelixHeadlessCombobox {
30
38
  customElements.define('acme-combobox', AcmeCombobox)
31
39
  ```
32
40
 
33
- That is the whole mechanism, and it is the same one the styled tier uses: it
34
- writes `static override tier = 'helix-'` and nothing else. The static appears 116
35
- times in the headless manifest, so it is discoverable rather than folklore.
41
+ That one line sets the prefix. The styled tier sets its prefix the same way, with
42
+ `static override tier = 'helix-'` and nothing else. The static appears 116 times
43
+ in the headless manifest, so you can find it there.
36
44
 
37
- ## The render graph is the part that will catch you
45
+ ## Register every component a component renders
38
46
 
39
- **A component that renders another gives you two things to register, and only
40
- one of them is obvious.**
47
+ **When a component renders another component, register both.**
41
48
 
42
- Register `acme-combobox` without also registering `acme-listbox` and the panel
43
- renders a tag nobody defined. That is not an error and not a warning: an
44
- unregistered custom element is an inert, unstyled inline box, so what you see is
45
- a combobox that appears not to open.
49
+ If you register `acme-combobox` without `acme-listbox`, the panel renders a tag
50
+ that is not defined. The browser shows no error or warning. An unregistered
51
+ custom element is an inert, unstyled inline box, so the combobox appears not to
52
+ open.
46
53
 
47
54
  [//]: # (renders)
48
55
 
@@ -71,22 +78,24 @@ a combobox that appears not to open.
71
78
 
72
79
  [//]: # (/renders)
73
80
 
74
- The safe rule is to subclass and register a family together with everything it
75
- renders, transitively: `command` reaches `dialog` and `listbox`, and `listbox`
76
- reaches `option`.
81
+ Subclass and register each family together with everything it renders, and
82
+ everything those families render in turn. For example, `command` reaches
83
+ `dialog` and `listbox`, and `listbox` reaches `option`.
84
+
85
+ We generate the table from the manifest, which publishes the graph as
86
+ `helix.renders` on every element that interpolates a tag. We kept the table by
87
+ hand until September 22, 2026. By then, four families in it were wrong. The
88
+ generated table is always current.
77
89
 
78
- **This table is generated from the manifest**, which publishes the graph as
79
- `helix.renders` on every element that interpolates a tag. It was kept by hand
80
- until 22 September 2026 and was wrong by four families when it stopped being, so
81
- read it as current rather than as maintained.
90
+ ## What you write yourself
82
91
 
83
- ## What you have to supply yourself
92
+ ### A `:not(:defined)` rule
84
93
 
85
- **A `:not(:defined)` guard.** `@fusion.dev/helix` ships an `elements.css` that
86
- hides each of its tags until the definition lands, so a page does not show a run
87
- of unstyled text and then snap. The headless package ships no such file, and
88
- nothing can generate one for tags you have not named yet. Write the rule for
89
- your own elements:
94
+ `@fusion.dev/helix` ships an `elements.css` that hides each of its tags until
95
+ the tag's definition loads. Your page then does not show unstyled text that
96
+ changes into components. The headless package ships no such file, and no tool
97
+ can generate one for tags you have not named yet. Write the rule for your own
98
+ elements:
90
99
 
91
100
  ```css
92
101
  acme-combobox:not(:defined),
@@ -95,12 +104,13 @@ acme-listbox:not(:defined) {
95
104
  }
96
105
  ```
97
106
 
98
- Visibility rather than `display`, so the page does not reflow when the
99
- definitions arrive.
107
+ Use `visibility` so the page does not reflow when the definitions arrive.
100
108
 
101
- **Your own typings, from the same generator we use.** `@fusion.dev/helix-cem`
102
- reads your package and writes `jsx.d.ts`, `vue.d.ts` and `svelte.d.ts` for your
103
- tags, with every member your subclass inherited from ours. Add a `cem.config.ts`
109
+ ### Typings for your tags
110
+
111
+ `@fusion.dev/helix-cem` is the generator we use for our own typings. It reads
112
+ your package and writes `jsx.d.ts`, `vue.d.ts`, and `svelte.d.ts` for your tags,
113
+ with every member your subclasses inherit from ours. Add a `cem.config.ts`
104
114
  beside your `package.json`:
105
115
 
106
116
  ```ts
@@ -113,11 +123,13 @@ export default {
113
123
  } satisfies HelixCemOptions
114
124
  ```
115
125
 
116
- and run `bun --bun helix-cem`. It finds what you extend through your
117
- `dependencies`, so `acme-combobox` arrives with the hundred-odd members it
118
- inherited rather than the two you wrote.
126
+ Then run `bun --bun helix-cem`. It finds the classes you extend through your
127
+ `dependencies`. The typings for `acme-combobox` then include the hundred or so
128
+ members it inherits, as well as the two you wrote.
129
+
130
+ ### The tag map
119
131
 
120
- **The tag map is still yours to write**, one line per element, beside the class:
132
+ Write the tag map yourself, with one line per element, beside the class:
121
133
 
122
134
  ```ts
123
135
  declare global {
@@ -127,43 +139,57 @@ declare global {
127
139
  }
128
140
  ```
129
141
 
130
- That is TypeScript's own convention for a custom element rather than a gap in
131
- this: the interface merges from your source, and nothing generated can name a
132
- class it is not in the same program as.
142
+ TypeScript declares custom elements this way. The interface merges from your
143
+ source, and a generated file cannot name a class that is not in the same
144
+ program.
145
+
146
+ ## What the headless tier handles for you
147
+
148
+ ### Tree-shaking
149
+
150
+ `@fusion.dev/helix-headless` declares `sideEffects: ["./dist/**/*.js"]`. The
151
+ declaration is accurate, because the modules register elements when you import
152
+ them. A bundler that treated them as free of side effects would drop a
153
+ registration, and a tag would never upgrade.
154
+
155
+ ### Documented parts
156
+
157
+ Every part has an `@csspart` entry, so every `::part()` you can use is
158
+ published. You write your presentation layer against these named parts, and it
159
+ does not depend on our internal markup.
160
+
161
+ ### Behavior
162
+
163
+ These features live below the tier you replace, so they keep working under your
164
+ tag names:
133
165
 
134
- ## What you get without asking
166
+ - focus management
167
+ - typeahead
168
+ - the roving tab stop
169
+ - form participation
170
+ - validity
135
171
 
136
- **Tree-shaking is honest.** `@fusion.dev/helix-headless` declares
137
- `sideEffects: ["./dist/**/*.js"]`, which is true rather than convenient: the
138
- modules register elements on import, so a bundler that believed otherwise would
139
- drop a registration and leave you debugging a tag that does not upgrade.
172
+ ## `tier` is not yet a versioned API
140
173
 
141
- **A styling surface that is documented.** Every part carries an `@csspart`, so
142
- `::part()` is a published door rather than a shadow tree you have to guess at.
143
- That is what makes replacing the presentation layer tractable: you are writing
144
- against named parts, not against our internals.
174
+ `tier` is an implementation detail that is visible in the manifest. Using it to
175
+ set your own prefix makes it an API that needs a stability contract, and we
176
+ have not written that contract yet. The pattern is supported but not yet
177
+ versioned, so pin your Helix version.
145
178
 
146
- **Composition stays ours.** Focus management, typeahead, the roving tab stop,
147
- form participation and validity all live below the tier you are replacing, so
148
- they keep working under your names.
179
+ ## Building on the headless tier compared with white-labeling
149
180
 
150
- ## What is not promised yet
181
+ Building on the headless tier fits you if you are building a design system on
182
+ top of ours and our tags can appear beside yours.
151
183
 
152
- `tier` is an implementation detail that happens to be visible in the manifest.
153
- Using it the way this page describes turns it into API with a stability contract
154
- attached, and that contract is not written. Treat this as a supported pattern
155
- that is not yet a versioned promise, and pin your Helix version.
184
+ White-labeling fits a customer who wants Helix shipped under their own name,
185
+ with no Helix tags. It costs more, and it needs:
156
186
 
157
- ## How this differs from white-labeling
187
+ - the tag literals rewritten at build time
188
+ - a second distribution to publish
189
+ - an artifact per customer
158
190
 
159
- Two different customers get confused for each other here. This page is for the
160
- one building a design system on top of ours and content for our tags to sit
161
- beside theirs. The other wants Helix shipped under their name with ours absent,
162
- which is a different and more expensive mechanism: rewriting the tag literals at
163
- build time, a second distribution to publish, and an artifact per customer.
164
- Nothing on this page needs any of that.
191
+ Building on the headless tier needs none of these.
165
192
 
166
- The ownership question answers itself in this direction. You hold the
167
- presentation layer, the tags and the build. If Fusion stopped tomorrow you would
168
- keep a working design system and lose upstream fixes to the behavior underneath
169
- it.
193
+ You own the presentation layer, the tags, and the build. If we stopped
194
+ tomorrow, you would keep a working design system. You would lose our fixes to
195
+ the behavior underneath it.
@@ -1,37 +1,49 @@
1
1
  ---
2
- description: The data channel nobody expects, and why it is a real table.
2
+ description: Which chart to use, and how charts read their data from a table in the document.
3
3
  section: Essentials
4
4
  title: Charting
5
5
  ---
6
6
 
7
7
  # Charting
8
8
 
9
- The chart families are `Bar Chart`, `Line Chart`, `Area Chart`,
10
- `Scatter Chart`, `Donut Chart`, `Heatmap`, `Sparkline`, `Trend` and the shared
11
- `Legend`. Each has its own API page. Here is which one answers which question,
12
- and how the data gets in, which is the same for all of them.
9
+ Helix has these chart families, and each one has its own API page:
13
10
 
14
- ## Which chart
11
+ - `Bar Chart`
12
+ - `Line Chart`
13
+ - `Area Chart`
14
+ - `Scatter Chart`
15
+ - `Donut Chart`
16
+ - `Heatmap`
17
+ - `Sparkline`
18
+ - `Trend`
19
+ - `Legend`, which all of the charts share
15
20
 
16
- Pick by the question, not by the picture.
21
+ This guide covers which chart fits which question, and how data gets into a
22
+ chart. Data gets in the same way for every chart.
23
+
24
+ ## Choose a chart
25
+
26
+ Choose a chart by the question it answers.
17
27
 
18
28
  - **How much, compared.** `Bar Chart`. A bar's length is its value, so it always
19
29
  starts at zero.
20
30
  - **How something moved over time.** `Line Chart`. It measures from the data's
21
31
  own range, so a small change still shows. Its `area` puts a light wash under
22
- each line, each drawn from the floor on its own and overlapping the others.
32
+ each line. Each wash is drawn from the floor on its own and overlaps the
33
+ others.
23
34
  - **How a total is made up over time.** `Area Chart`. Each column is stacked on
24
35
  the one below, so the top edge is the total and a band's thickness is its
25
- share. This is the one to reach for when the parts add up to something, and
26
- `Line Chart` with `area` is not a substitute: that overlaps the series, this
27
- adds them.
36
+ share. Use it when the parts add up to a total. `Line Chart` with `area`
37
+ overlaps the series, and `Area Chart` adds them.
28
38
  - **Parts of one whole, at one moment.** `Donut Chart`.
29
- - **Whether two measures relate.** `Scatter Chart`, one point per row.
30
- - **How each day or check went.** `Heatmap`: uptime, contributions, activity.
31
- - **The shape of a series beside its number.** `Sparkline`, with no axes. And
32
- `Trend` for which way one measurement moved and whether that is good news.
39
+ - **Whether two measures relate.** `Scatter Chart`, with one point per row.
40
+ - **How each day or check went.** `Heatmap`, for uptime, contributions, or
41
+ activity.
42
+ - **The shape of a series beside its number.** `Sparkline`, drawn with no axes.
43
+ Use `Trend` to show which way one measurement moved and whether that is good
44
+ news.
33
45
 
34
- ## The data is a table in the document
46
+ ## Charts read their data from a table
35
47
 
36
48
  ```html
37
49
  <table id="revenue">
@@ -48,20 +60,19 @@ Pick by the question, not by the picture.
48
60
  <helix-bar-chart for="revenue"></helix-bar-chart>
49
61
  ```
50
62
 
51
- `for` points at a real `<table>` by id, and the chart reads its series from it.
52
- That is unlike every other component in the library, and it is not a
53
- convenience.
63
+ `for` points to a real `<table>` by id, and the chart reads its series from that
64
+ table. No other Helix component gets its data this way. There are two reasons.
54
65
 
55
- **A property cannot survive hydration.** A framework's server render emits
56
- markup, and a property is not markup: an array assigned to `items` exists only
66
+ First, a property does not survive hydration. A framework's server render emits
67
+ markup, and a property is not markup. An array assigned to `items` exists only
57
68
  after JavaScript has run, so the server has nothing to send and the first paint
58
- has nothing to draw. Text in the document is the one channel that both a server
59
- and a client can see.
69
+ has nothing to draw. Text in the document is the one channel that both the
70
+ server and the client can see.
60
71
 
61
- **And the table is not a workaround, it is the accessible version.** A chart is
62
- a picture of numbers, and a screen reader cannot read a picture. The table is
63
- the numbers, in the document, navigable, and the chart is the drawing of them.
64
- Hide the table visually if it should not be seen, and the data is still there:
72
+ Second, the table is what a screen reader reads. A chart is a picture of
73
+ numbers, and a screen reader cannot read a picture. The table holds the numbers
74
+ in the document, where you can navigate them, and the chart draws them. If the
75
+ table should not be seen, hide it visually, and the data is still there:
65
76
 
66
77
  ```html
67
78
  <table
@@ -70,67 +81,75 @@ Hide the table visually if it should not be seen, and the data is still there:
70
81
  >…</table>
71
82
  ```
72
83
 
73
- The caption becomes the chart's accessible name unless you set `label`, which is
74
- usually the right words and is already written.
84
+ The table's caption becomes the chart's accessible name unless you set `label`.
85
+ The caption usually has the right words already.
75
86
 
76
87
  ## Series colors
77
88
 
78
- Twenty-four `--helix-color-series-*` tokens, in order. A chart with three series
79
- uses the first three. They are ordered to stay distinguishable in that order
80
- rather than to look good as a full set of twenty-four.
89
+ Helix has twenty-four series color tokens, in order, from
90
+ `--helix-color-series-1` to `--helix-color-series-24`. A chart with three series
91
+ uses the first three. The tokens are ordered so that each color
92
+ stays distinguishable from the ones before it. They are not designed to look
93
+ good as a full set of twenty-four.
81
94
 
82
- The palette wraps, and where it wraps is one number in one place, so a chart and
83
- the legend beside it can never disagree about which color a series is.
95
+ The palette wraps after the last color. One number in one place sets where it
96
+ wraps, so a chart and the legend beside it always agree on each series' color.
84
97
 
85
- **A chart's mark carries its own series color as a custom property**, because a
86
- chart knows which series a bar belongs to and CSS cannot count it. That is what
87
- lets you restyle a series from outside without knowing the drawing order.
98
+ Each mark in a chart carries its series color as a custom property. The chart
99
+ tracks which series each bar belongs to, and CSS cannot count that. With the
100
+ custom property, you can restyle a series from outside the chart without knowing
101
+ the drawing order.
88
102
 
89
- ## Legends
103
+ ## Add a legend
90
104
 
91
105
  ```html
92
106
  <helix-legend for="revenue"></helix-legend>
93
107
  <helix-bar-chart for="revenue"></helix-bar-chart>
94
108
  ```
95
109
 
96
- The legend reads the same table, so the names and the colors cannot disagree
97
- with the chart's. Pointing them at two different tables is the only way to make
98
- them disagree, and it is not something to do by accident.
99
-
100
- ## Right-to-left
101
-
102
- On a page with `dir="rtl"`, an axis that follows reading order starts where the
103
- text does, on the right: categories and time. The words around a drawing are
104
- HTML and turn on their own, and the drawing turns with them, so the name under
105
- a column is that column's name in either direction. The pointer and the tooltip
106
- read the drawing the same way. An axis of values keeps its own direction.
107
-
108
- - **What turns.** `Bar Chart`'s columns, and its rows, which grow out of their
109
- names at the right. `Line Chart`, `Area Chart` and `Sparkline`, with their
110
- end marks. `Heatmap`'s weeks, which were already a grid laid out along the
111
- line. A half `Donut Chart`, which is read across.
112
- - **What does not.** Up is more in every script, so values keep their vertical
113
- sense, and numerals are text beside the drawing, so none reads backwards. A
114
- whole `Donut Chart` keeps its first slice at twelve and runs clockwise, which
115
- is a clock's convention rather than a script's. `Scatter Chart` is laid out as
116
- on a left-to-right page, its y axis on the left and more to the right, because
117
- both of its axes are measures and a number line runs that way in every
118
- script. Its axis names read in their own direction, so a name in Arabic reads
119
- right to left under the plot's far end, and its summary and tooltip read the
120
- way the page does.
121
-
122
- A chart that should read left to right anyway, a number line in a mathematics
123
- text for instance, takes `dir="ltr"` on the element, and the platform's own
124
- attribute is the whole of the switch.
125
-
126
- ## Reduced motion
127
-
128
- Charts animate on entry and on data change, and every one of them answers
129
- `prefers-reduced-motion`. See [Motion](./motion).
130
-
131
- ## What these are not
132
-
133
- **Not a charting library.** There is no axis configuration language, no plugin
134
- system, and no chart type you build by composing scales. Drawings that read a
135
- table, styled by the token system, with an accessible representation by
136
- construction. When you need a grammar of graphics, use one.
110
+ The legend reads the same table as the chart, so their names and colors always
111
+ match. They can differ only if you point them at two different tables.
112
+
113
+ ## Charts on right-to-left pages
114
+
115
+ On a page with `dir="rtl"`, an axis that follows reading order starts on the
116
+ right, where the text starts. Categories and time follow reading order. The
117
+ words around a chart are HTML and change direction on their own. The drawing
118
+ changes direction with them, so the name under a column belongs to that column
119
+ in either direction. The pointer and the tooltip read the drawing the same way.
120
+ An axis of values keeps its own direction.
121
+
122
+ These parts change direction:
123
+
124
+ - `Bar Chart`'s columns, and its rows, which grow out of their names at the
125
+ right
126
+ - `Line Chart`, `Area Chart`, and `Sparkline`, with their end marks
127
+ - `Heatmap`'s weeks, which were already a grid laid out along the line
128
+ - A half `Donut Chart`, which is read across
129
+
130
+ These parts keep their direction:
131
+
132
+ - Values keep their vertical direction, because up means more in every script.
133
+ - Numerals are text beside the drawing, so none of them reads backwards.
134
+ - A whole `Donut Chart` keeps its first slice at twelve o'clock and runs
135
+ clockwise. That is a clock's convention, and it does not depend on the script.
136
+ - `Scatter Chart` is laid out as on a left-to-right page, with its y axis on the
137
+ left and larger values to the right. Both of its axes are measures, and a
138
+ number line runs that way in every script. Its axis names read in their own
139
+ direction, so a name in Arabic reads right to left under the far end of the
140
+ plot. Its summary and tooltip follow the page's direction.
141
+
142
+ To keep a chart left to right on a right-to-left page, such as a number line in
143
+ a mathematics text, set `dir="ltr"` on the chart element. You need nothing else.
144
+
145
+ ## Chart animation and reduced motion
146
+
147
+ Charts animate when they appear and when their data changes. Every chart
148
+ responds to `prefers-reduced-motion`. See [Motion](./motion).
149
+
150
+ ## What Helix charts do not include
151
+
152
+ Helix charts have no axis configuration language, no plugin system, and no chart
153
+ types that you build by composing scales. Each chart is a drawing that reads a
154
+ table and is styled by the token system, and the table is its accessible
155
+ representation. When you need a grammar of graphics, use a charting library.