actual-css 0.5.0 → 0.6.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 (86) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/actual.css +1 -0
  3. package/dist/actual.full.css +480 -117
  4. package/dist/actual.full.js +1 -1
  5. package/dist/actual.full.min.css +1 -1
  6. package/dist/actual.min.css +1 -1
  7. package/docs/design-notes/browser-support.md +14 -14
  8. package/docs/design-notes/enhancement-contract.md +30 -13
  9. package/docs/design-notes/forced-colors.md +11 -7
  10. package/docs/design-notes/grid.md +4 -4
  11. package/docs/design-notes/naming.md +15 -9
  12. package/docs/design-notes/platform-alignment.md +9 -0
  13. package/docs/design-notes/references.md +4 -0
  14. package/docs/design-notes/steps.md +748 -0
  15. package/docs/design-notes/widget-primitives.md +32 -15
  16. package/docs/navigation.json +1 -0
  17. package/docs/pages/components/alert.md +13 -8
  18. package/docs/pages/components/aura.md +102 -6
  19. package/docs/pages/components/avatar.md +9 -6
  20. package/docs/pages/components/badge.md +11 -7
  21. package/docs/pages/components/button.md +17 -17
  22. package/docs/pages/components/card.md +15 -8
  23. package/docs/pages/components/chat.md +1 -1
  24. package/docs/pages/components/dialog.md +10 -7
  25. package/docs/pages/components/drawer.md +1 -1
  26. package/docs/pages/components/fab.md +12 -10
  27. package/docs/pages/components/indicator.md +6 -6
  28. package/docs/pages/components/list.md +11 -2
  29. package/docs/pages/components/navbar.md +1 -1
  30. package/docs/pages/components/pagination.md +1 -1
  31. package/docs/pages/components/rating.md +4 -4
  32. package/docs/pages/components/skeleton.md +1 -1
  33. package/docs/pages/components/spinner.md +1 -1
  34. package/docs/pages/components/steps.md +376 -52
  35. package/docs/pages/components/table.md +5 -5
  36. package/docs/pages/enhancements/flyout.md +12 -10
  37. package/docs/pages/enhancements/overview.md +2 -2
  38. package/docs/pages/enhancements/scrollspy.md +1 -1
  39. package/docs/pages/enhancements/tabs.md +1 -1
  40. package/docs/pages/examples/overview.md +2 -0
  41. package/docs/pages/forms/choice-cards.md +4 -4
  42. package/docs/pages/forms/combobox.md +87 -0
  43. package/docs/pages/forms/floating-field.md +5 -3
  44. package/docs/pages/forms/joined-controls.md +4 -4
  45. package/docs/pages/forms/labels.md +8 -5
  46. package/docs/pages/forms/overview.md +25 -18
  47. package/docs/pages/forms/password.md +3 -2
  48. package/docs/pages/forms/range.md +13 -2
  49. package/docs/pages/forms/states-and-sizes.md +6 -4
  50. package/docs/pages/forms/validation.md +13 -9
  51. package/docs/pages/foundations/tokens.md +9 -6
  52. package/docs/pages/foundations/typography.md +1 -1
  53. package/docs/pages/guides/bootstrap.md +3 -3
  54. package/docs/pages/guides/introduction.md +1 -1
  55. package/docs/pages/guides/modular-import.md +21 -10
  56. package/docs/pages/guides/progressive-enhancement.md +75 -54
  57. package/docs/pages/guides/tailwind.md +2 -2
  58. package/docs/pages/layout/app-shell.md +4 -4
  59. package/docs/pages/layout/choosing.md +10 -6
  60. package/docs/pages/layout/grid.md +11 -10
  61. package/docs/pages/layout/stack.md +10 -6
  62. package/docs/pages/patterns/structured-lists.md +7 -7
  63. package/docs/pages/utilities/accessibility.md +1 -1
  64. package/docs/pages/utilities/flex.md +20 -13
  65. package/docs/pages/utilities/links.md +1 -1
  66. package/docs/pages/utilities/list.md +1 -1
  67. package/docs/pages/utilities/overflow.md +14 -7
  68. package/docs/pages/utilities/overview.md +22 -0
  69. package/docs/pages/utilities/shape.md +1 -1
  70. package/docs/pages/utilities/sizing-wrapping.md +10 -8
  71. package/docs/pages/utilities/spacing.md +26 -19
  72. package/docs/pages/utilities/text.md +1 -1
  73. package/llms.txt +27 -4
  74. package/package.json +3 -2
  75. package/scripts/reserved-classes.json +4 -1
  76. package/src/css/components/fab.css +44 -8
  77. package/src/css/components/list.css +3 -1
  78. package/src/css/components/steps.css +277 -69
  79. package/src/css/core/tokens.css +1 -0
  80. package/src/css/effects/aura.css +101 -11
  81. package/src/css/forms/custom-select.css +1 -1
  82. package/src/css/forms/floating-field.css +8 -6
  83. package/src/css/layout/container-query.css +37 -13
  84. package/src/css/layout/grid.css +7 -7
  85. package/src/css/layout/index.css +1 -1
  86. package/src/js/password.js +1 -1
@@ -1,65 +1,389 @@
1
1
  # Steps
2
2
 
3
- > Semantic ordered-list progression for a multi-step process.
3
+ > Progress through a short multi-step flow.
4
4
 
5
- Use an `<ol>` because order is part of the meaning. Add `.complete` to finished
6
- steps and `aria-current="step"` to exactly one current step. Unmarked items are
7
- future steps. The component needs no JavaScript.
5
+ Use an `<ol>` because the order is part of the meaning. Add `.step-complete` to
6
+ finished steps and `aria-current="step"` to the current one. Unmarked steps are
7
+ upcoming.
8
8
 
9
- The three states are distinct without any glyph: future is neutral, complete is
10
- a filled marker with an accented connector, current is an outlined marker with a
11
- thicker ring. The accented connector reads as "already walked", so the segment
12
- leaving the current step stays neutral. A step carrying both states renders
13
- entirely as current — marker, glyph, and connector.
9
+ Orientation and labels are two independent choices.
10
+
11
+ `.steps` is the component; the orientation is a second class, and it is always
12
+ required:
13
+
14
+ | Markup | Orientation | Stages |
15
+ | ------------------------------------- | ----------- | -------- |
16
+ | `<ol class="steps steps-horizontal">` | horizontal | 2 to 5 |
17
+ | `<ol class="steps steps-vertical">` | vertical | no limit |
18
+
19
+ Neither orientation is the default, so `.steps` on its own is incomplete markup.
20
+ Everything a step *is* — `.step-label`, `.step-complete`, `aria-current="step"`,
21
+ the marker and its states — comes from `.steps` and is identical in both. The
22
+ second class only decides how the sequence is laid out.
23
+
24
+ For a horizontal sequence longer than five stages, use `.steps-vertical` or
25
+ another progression pattern.
26
+
27
+ Step labels are then the other choice, and it is **optional in either
28
+ orientation**. A sequence is either entirely labelled or entirely unlabelled:
29
+
30
+ | | Empty steps | `.step-label` on every step |
31
+ | -------------- | ------------------- | ------------------------------------- |
32
+ | **horizontal** | compact progression | named sequence, stacked or inline |
33
+ | **vertical** | compact rail | named sequence, labels beside markers |
34
+
35
+ - **Unlabelled steps are visual progress markers.** The surrounding interface
36
+ communicates the current step and position.
37
+ - **Labelled steps carry the sequence names themselves**, and may use
38
+ `a.step-label` for navigation. Actual CSS never hides an authored label to
39
+ solve a layout constraint.
40
+
41
+ The component needs no JavaScript.
14
42
 
15
43
  **Related terms:** stepper, progress steps, step indicator, wizard steps, multi-step progress.
16
44
 
17
- ## Class reference
45
+ ## Basic usage
46
+
47
+ ```html demo
48
+ <ol class="steps steps-horizontal">
49
+ <li class="step-complete"><span class="step-label">Account</span></li>
50
+ <li aria-current="step"><span class="step-label">Payment</span></li>
51
+ <li><span class="step-label">Confirm</span></li>
52
+ </ol>
53
+ ```
54
+
55
+ The three states stay distinct even without a checkmark:
56
+
57
+ - **Upcoming** — neutral marker
58
+ - **Complete** — filled marker and completed connector
59
+ - **Current** — outlined marker with a stronger ring
60
+
61
+ Only one step should use `aria-current="step"`.
62
+
63
+ The marker carries the state, so the label sits a notch below it: one size
64
+ smaller than body text, and neutral in weight. Only the current step's label is
65
+ emphasised — it is where you are now. A completed step needs no bold text; its
66
+ filled marker already says as much.
67
+
68
+ ## Horizontal steps
69
+
70
+ `.steps-horizontal` is designed for **2 to 5 stages**.
71
+
72
+ ### Without labels — visual progress only
73
+
74
+ Leave the items empty when the surrounding interface already says where the
75
+ user is. The row is then a drawn `3 / 5`, and the page carries the words:
76
+
77
+ ```html demo
78
+ <div class="stack">
79
+ <hgroup>
80
+ <p class="overline">Step 3 of 5</p>
81
+ <h3>Validation</h3>
82
+ </hgroup>
83
+
84
+ <ol class="steps steps-horizontal" aria-hidden="true">
85
+ <li class="step-complete"></li>
86
+ <li class="step-complete"></li>
87
+ <li aria-current="step"></li>
88
+ <li></li>
89
+ <li></li>
90
+ </ol>
91
+ </div>
92
+ ```
93
+
94
+ ```text
95
+ ●────────●────────③────────○────────○
96
+ ```
97
+
98
+ This form fits from phone width to desktop with no container query and no
99
+ variant class: with no label to make room for, a step only needs its marker.
100
+
101
+ The track runs edge to edge, so it lines up with the text around it. There is
102
+ no label to centre a marker against, so each marker takes the start of its own
103
+ share of the row and its connector fills the rest.
104
+
105
+ Hide it from assistive technology with `aria-hidden="true"`. A list of empty
106
+ `<li>`s whose numbers come from CSS is not a useful sequence to announce, and
107
+ the `hgroup` above already carries the accessible information — position and
108
+ step name. An unlabelled step is never interactive, so nothing focusable is
109
+ being hidden.
110
+
111
+ > An empty step means genuinely empty — no text, not even whitespace.
112
+ > `<li></li>` is a marker; `<li> </li>` is not. Same rule as `.badge:empty`.
18
113
 
19
- | Class | Kind | Description |
20
- |-------------------------|-----------|--------------------------------------------|
21
- | `.steps` | Component | Ordered progression with numbered markers. |
22
- | `.complete` | State | A finished step: filled marker. |
23
- | `[aria-current="step"]` | State | The current step: outlined marker. |
114
+ ### With labels — the sequence carries the names
115
+
116
+ Add `.step-label` to every step when the stepper itself should expose the step
117
+ names, or when a step should be navigable:
24
118
 
25
119
  ```html demo
26
- <ol class="steps">
27
- <li class="complete">Account</li>
28
- <li aria-current="step">Payment</li>
29
- <li>Confirm</li>
120
+ <ol class="steps steps-horizontal" aria-label="Checkout progress">
121
+ <li class="step-complete"><span class="step-label">Account</span></li>
122
+ <li class="step-complete"><span class="step-label">Profile</span></li>
123
+ <li aria-current="step"><span class="step-label">Validation</span></li>
124
+ <li><span class="step-label">Payment</span></li>
30
125
  </ol>
31
126
  ```
32
127
 
33
- ## Intrinsic responsiveness
34
-
35
- `.steps` fills its row when the steps fit and holds each item at `--step-min`
36
- otherwise, so the sequence scrolls horizontally only when it genuinely cannot
37
- fit — no breakpoint. The threshold is space-driven: how many steps fit depends
38
- on their number and the configurable minimum item width `--step-min`. Labels
39
- wrap inside their item when needed.
40
-
41
- Because `.steps` is an `<ol>` that can scroll horizontally, its overflow is not
42
- focusable by default in every browser. Prefer a `--step-min` that fits the
43
- common case, and only give a step flow `tabindex="0"` when your content
44
- genuinely needs keyboard access to the overflow — the framework adds neither
45
- JavaScript nor a tabindex automatically.
46
-
47
- Keep state classes aligned with the real process state; they are visual, while
48
- `aria-current="step"` also exposes the current position to assistive technology.
49
- Do not put links or buttons around a step unless the workflow genuinely allows
50
- the user to navigate to it.
51
-
52
- ### Hooks
53
-
54
- - `--step-size` — marker diameter.
55
- - `--step-min` — minimum item width; below this the sequence scrolls instead of
56
- squishing labels.
57
- - `--step-gap` — space between each marker and label.
58
- - `--step-line-size` — connector thickness.
59
- - `--step-marker-radius` — marker corner radius (round by default).
60
- - `--step-connector` — connector background; when set it overrides the color
61
- (defaults to each step's own line, so a `.complete` step's connector follows
62
- its selected color). A plain color by default, but any background (e.g. a
63
- dashed `repeating-linear-gradient`) works.
64
- - `--step-complete-mark` — replaces the number on a `.complete` step with any
65
- `content` value (e.g. `"✓"`); defaults to the step number.
128
+ **Actual CSS never hides an authored step label.** Labels stay visible at every
129
+ width. If a labelled row does not fit its space, it scrolls — and the honest
130
+ answers to that are more room, fewer stages, or `.steps-vertical`.
131
+
132
+ Since scrolling is the fallback, a labelled row is worth pairing with
133
+ `.scroller`, which gives the native scrollbar the theme's density and colour
134
+ instead of the OS default:
135
+
136
+ ```html
137
+ <ol class="steps steps-horizontal scroller">
138
+ ```
139
+
140
+ Steps does not apply it for you, because scrollbar treatment is an app-wide
141
+ decision rather than a per-component one. Every other scroll container —
142
+ `.table`, a `.flyout`, a scrolling `dialog` — leaves the scrollbar alone too,
143
+ so a page that thinned only its stepper would show two kinds of scrollbar. Put
144
+ `.scroller` on whatever scrolls, once. See the sizing and wrapping page for its
145
+ hooks.
146
+
147
+ Do not add `.stable-gutter` here. It reserves gutter on the inline axis, for a
148
+ vertical scrollbar this row never draws, so it narrows the row instead of
149
+ steadying its height.
150
+
151
+ ### One presentation enhancement
152
+
153
+ With generous room, a labelled row moves marker and label inline and lets the
154
+ connector absorb the free space between groups:
155
+
156
+ ```text
157
+ normal space
158
+ ✓──────────2──────────3
159
+ Account Payment Confirm
160
+
161
+ generous space
162
+ ✓ Account ───────── 2 Payment ───────── 3 Confirm
163
+ ```
164
+
165
+ Stacked is the baseline and is fully functional on its own. The inline form is
166
+ an enhancement, and it needs an `actual-container` size context the author
167
+ grants.
168
+
169
+ Resize the demo below. The 3-step flow needs less room than the supported
170
+ 5-step maximum.
171
+
172
+ ```html demo resize
173
+ <div class="stack">
174
+ <ol class="steps steps-horizontal container-query scroller" style="--step-complete-mark: '✓'">
175
+ <li class="step-complete"><span class="step-label">Identification</span></li>
176
+ <li aria-current="step"><span class="step-label">Confirmation</span></li>
177
+ <li><span class="step-label">Finalisation</span></li>
178
+ </ol>
179
+
180
+ <ol class="steps steps-horizontal container-query scroller" style="--step-complete-mark: '✓'">
181
+ <li class="step-complete"><span class="step-label">Account</span></li>
182
+ <li class="step-complete"><span class="step-label">Details</span></li>
183
+ <li aria-current="step"><span class="step-label">Payment</span></li>
184
+ <li><span class="step-label">Review</span></li>
185
+ <li><span class="step-label">Confirm</span></li>
186
+ </ol>
187
+ </div>
188
+ ```
189
+
190
+ `.container-query` is only a convenience helper. You can grant the same shared
191
+ context in your own CSS:
192
+
193
+ ```css
194
+ .checkout-steps {
195
+ container: actual-container / inline-size;
196
+ }
197
+ ```
198
+
199
+ A named wrapper works too; the stepper responds to the nearest
200
+ `actual-container` region.
201
+
202
+ One threshold decides it: from **60rem**, a labelled row goes inline; below it,
203
+ stacked. That is calibrated on five stages, the widest supported row, because
204
+ it is where a five-stage row still leaves its connector a real region rather
205
+ than a stub. Inline is a bonus for generous room, so switching late costs
206
+ nothing, and the same threshold then serves every stage count.
207
+
208
+ The step count changes nothing else. Whether a row has two stages or five, its
209
+ labels stay visible and it scrolls if it must.
210
+
211
+ Without an `actual-container`, or without container-query / `:has()` support,
212
+ the stacked layout remains fully functional. The unlabelled form needs neither:
213
+ it is compact by structure, not by query.
214
+
215
+ > `.container-query` uses inline-size containment. Put it where width comes from
216
+ > the layout context, not on a shrink-to-fit box. See the container-query helper
217
+ > for the full containment guidance.
218
+
219
+ ## Vertical steps
220
+
221
+ Vertical steps are an explicit orientation, not a mobile fallback, and they are
222
+ not bound by the horizontal 2–5 stage limit.
223
+
224
+ Use `.steps steps-vertical` when the surrounding layout is naturally vertical —
225
+ for example a wizard sidebar or a narrow process panel. It is a peer of
226
+ `.steps-horizontal`, not a modifier on it: never write the two together.
227
+
228
+ ```html demo
229
+ <ol class="steps steps-vertical" style="--step-complete-mark: '✓'">
230
+ <li class="step-complete"><span class="step-label">Basic details</span></li>
231
+ <li class="step-complete"><span class="step-label">Company details</span></li>
232
+ <li aria-current="step"><span class="step-label">Subscription plan</span></li>
233
+ <li><span class="step-label">Payment details</span></li>
234
+ </ol>
235
+ ```
236
+
237
+ The state model is identical to horizontal steps. The composition is simply
238
+ different: markers form a vertical track and labels sit beside them.
239
+
240
+ ### A compact rail
241
+
242
+ Leaving the items empty works here too, and gives a marker rail — useful for a
243
+ narrow sticky sidebar next to content that names the step:
244
+
245
+ ```html demo
246
+ <div class="cluster">
247
+ <ol class="steps steps-vertical" aria-hidden="true">
248
+ <li class="step-complete"></li>
249
+ <li class="step-complete"></li>
250
+ <li aria-current="step"></li>
251
+ <li></li>
252
+ <li></li>
253
+ </ol>
254
+
255
+ <hgroup>
256
+ <p class="overline">Step 3 of 5</p>
257
+ <h3>Validation</h3>
258
+ </hgroup>
259
+ </div>
260
+ ```
261
+
262
+ The rail is exactly as wide as its markers, so it costs nothing in a
263
+ shrink-to-fit column.
264
+
265
+ Vertical steps stay vertical at every width. The container query only refines
266
+ the horizontal orientation.
267
+
268
+ There is no fixed stage count for the vertical orientation. A longer sequence is
269
+ fine as long as it remains useful and readable in its surrounding layout.
270
+
271
+ ## Connectors
272
+
273
+ Steps uses a line between markers by default.
274
+
275
+ `--step-connector` controls the default horizontal connector background. It
276
+ accepts a complete CSS background value, so a theme can replace the line with a
277
+ gradient, image or nothing at all.
278
+
279
+ In the wide horizontal representation, the connector expands into the free
280
+ space between marker + label groups. A theme can replace only that representation
281
+ with `--step-inline-connector`, for example a custom chevron SVG:
282
+
283
+ ```css
284
+ .checkout-steps {
285
+ --step-inline-connector:
286
+ url("../icons/chevron.svg") center / 1rem 1rem no-repeat;
287
+ }
288
+ ```
289
+
290
+ Vertical steps have no connector hook of their own. The vertical geometry is
291
+ different, so a horizontal value cannot transpose onto it — override
292
+ `.steps-vertical > li::after` directly if a design ever needs to.
293
+
294
+ Connectors are decorative. The ordered list and its labels carry the meaning of
295
+ the sequence.
296
+
297
+ ## Navigation
298
+
299
+ Steps are informational by default, and **only a labelled step can be
300
+ navigable**: navigation is expressed by making a `.step-label` an `<a href>`.
301
+ Markers are never interactive, so an unlabelled row is visual progress and
302
+ nothing more.
303
+
304
+ The `<a href>` is the whole interactive surface: a `<button>` or any other
305
+ focusable element inside a step is outside the component contract. Only make a
306
+ label a link when the workflow genuinely allows navigation to that step:
307
+
308
+ ```html demo resize
309
+ <ol class="steps steps-horizontal container-query scroller">
310
+ <li class="step-complete">
311
+ <a class="step-label" href="#">Account</a>
312
+ </li>
313
+ <li class="step-complete">
314
+ <a class="step-label" href="#">Details</a>
315
+ </li>
316
+ <li aria-current="step">
317
+ <span class="step-label">Payment</span>
318
+ </li>
319
+ <li>
320
+ <span class="step-label">Confirm</span>
321
+ </li>
322
+ </ol>
323
+ ```
324
+
325
+ Keep `aria-current="step"` on the current `<li>`.
326
+
327
+ A step link keeps the colour of its own state rather than the theme's `--link`,
328
+ so the marker states stay the strongest signal in the row. Its underline, hover
329
+ and focus ring are untouched — that is what marks it as navigable. If a touch
330
+ target needs to be more generous, put `.touch-target` on the anchor rather than
331
+ growing the stepper.
332
+
333
+ ## Hooks
334
+
335
+ On `.steps`, so both orientations read them:
336
+
337
+ - `--step-size` — marker diameter
338
+ - `--step-inline-gap` — spacing between marker, label and connector inline
339
+ - `--step-line-size` — connector thickness
340
+ - `--step-marker-radius` — marker corner radius
341
+ - `--step-complete-mark` — content used instead of the number on completed steps
342
+
343
+ `.steps-horizontal` only:
344
+
345
+ - `--step-min` — minimum item width in the stacked horizontal layout
346
+ - `--step-gap` — marker-to-label space in the stacked horizontal layout
347
+ - `--step-connector` — default horizontal connector background
348
+ - `--step-inline-connector` — optional connector background for wide horizontal steps
349
+
350
+ `.steps-vertical` only:
351
+
352
+ - `--step-vertical-gap` — space between vertical steps
353
+
354
+ ## Notes
355
+
356
+ Do not mix labelled and unlabelled steps in one sequence. Each step is sized on
357
+ its own content, so a mixed sequence renders a narrow marker between reading-
358
+ width steps — it lays out, but it reads as a gap rather than as progress.
359
+
360
+ A step name belongs in a `.step-label`. Bare text in an `<li>` is outside the
361
+ contract: it is content, so it gets a reading width like a label, but no rule
362
+ places or aligns it.
363
+
364
+ The **2 to 5** range applies to the horizontal orientation, and the inline
365
+ threshold is calibrated for it. A longer horizontal sequence is out of
366
+ contract: it still renders, but the geometry was never designed for that count.
367
+
368
+ The vertical orientation has no equivalent hard limit; its practical limit is
369
+ the surrounding layout and whether the sequence remains useful to scan.
370
+
371
+ An unlabelled sequence intentionally leaves presentation of the current step
372
+ name to the surrounding interface. If a narrow layout needs every step name
373
+ visible at once, a labelled `.steps-vertical` is usually the better
374
+ composition.
375
+
376
+ In Windows forced-colors mode the accent fill is dropped, so a completed marker
377
+ and an upcoming one both render as a ringed disc with a number. Set
378
+ `--step-complete-mark` — a checkmark, for instance — if your flow needs the two
379
+ to stay distinguishable there. Steps deliberately ships no forced-colors
380
+ override of its own: painting the marker `Highlight` makes the number or glyph
381
+ inside it unreadable, which is worse than the ambiguity it removes.
382
+
383
+ The inline threshold is calibrated to the default `--step-min`. Container
384
+ queries cannot read custom properties, so changing `--step-min` moves the
385
+ scroll budget but not the threshold.
386
+
387
+ See [Steps representations and thresholds](https://github.com/lekoala/actual-css/blob/master/docs/design-notes/steps.md)
388
+ for why the contract is shaped this way, and which alternatives were measured
389
+ and rejected.
@@ -12,11 +12,11 @@
12
12
 
13
13
  ## Class reference
14
14
 
15
- | Class | Kind | Description |
16
- |-----------------|-----------|--------------------------------------------------------------|
17
- | `.table-wrap` | Component | Scroll container and outer chrome (surface, border, radius). |
18
- | `.table` | Component | The table itself; row and cell rules. |
19
- | `.table.compact`| Density | Tighter cell padding; typography is unchanged. |
15
+ | Class | Kind | Description |
16
+ | ---------------- | --------- | ------------------------------------------------------------ |
17
+ | `.table-wrap` | Component | Scroll container and outer chrome (surface, border, radius). |
18
+ | `.table` | Component | The table itself; row and cell rules. |
19
+ | `.table.compact` | Density | Tighter cell padding; typography is unchanged. |
20
20
 
21
21
  ## Basic usage
22
22
 
@@ -6,16 +6,18 @@
6
6
 
7
7
  ## Class reference
8
8
 
9
- | Class | Kind | Description |
10
- |-------------------|-------------|----------------------------------------------------------------------|
11
- | `.flyout-trigger` | Composition | Positioning wrapper for a trigger and its panel. |
12
- | `.stretch` | Modifier | Stretches a `.flyout-trigger` to span its container. |
13
- | `.flyout` | Component | Floating action or nav surface, positioned by JavaScript. |
14
- | `.menu` | Component | Action-list primitive with strict `.menu > li > .menu-item` anatomy. |
15
- | `.menu-item` | Component | One action row; participates in roving focus. |
16
- | `.menu-item-icon` | Slot | Fixed leading column for a decorative icon. |
17
- | `.menu-item-text` | Slot | Flexible label column; truncates when the row is constrained. |
18
- | `.menu-item-end` | Slot | Trailing metadata such as a shortcut, badge, or status. |
9
+ | Class | Kind | Description |
10
+ | ----------------- | ----------- | ------------------------------------------- |
11
+ | `.flyout-trigger` | Composition | Positioning wrapper for trigger and panel. |
12
+ | `.stretch` | Modifier | Spans a `.flyout-trigger` to its container. |
13
+ | `.flyout` | Component | Floating surface, positioned by JavaScript. |
14
+ | `.menu` | Component | Action-list primitive. |
15
+ | `.menu-item` | Component | One action row; joins roving focus. |
16
+ | `.menu-item-icon` | Slot | Fixed leading column for an icon. |
17
+ | `.menu-item-text` | Slot | Flexible label column; truncates. |
18
+ | `.menu-item-end` | Slot | Trailing shortcut, badge or status. |
19
+
20
+ `.menu` has a strict `.menu > li > .menu-item` anatomy.
19
21
  | `.menu-label` | Variant | Muted section heading inside a menu; not interactive. |
20
22
  | `.menu-separator` | Variant | Divider between menu groups (`<hr role="separator">`). |
21
23
  | `.sm` / `.lg` | Variant | Compact or large density. |
@@ -15,7 +15,7 @@ class API, shared tokens, and progressive enhancement.
15
15
 
16
16
  ## Modules
17
17
 
18
- The full runtime is `actual-css/js`. Each enhancer is also importable on its own
18
+ The full runtime is `actual-css/js/full`. Each enhancer is also importable on its own
19
19
  for projects that use custom components or want a smaller behavior surface:
20
20
 
21
21
  ```js
@@ -32,5 +32,5 @@ is a no-op until the module is loaded again with a DOM.
32
32
 
33
33
  Each interactive component has its own page documenting the exact markup its
34
34
  enhancement expects: Dialog, Drawer, Flyout, Tooltip, Tabs, Scrollspy, and
35
- Status Bar. The default runtime is loaded on the docs pages, so the examples
35
+ Status Bar. The full runtime is loaded on the docs pages, so the examples
36
36
  work with the documented markup alone.
@@ -9,7 +9,7 @@ or style `[aria-current]` yourself.
9
9
  ## Class reference
10
10
 
11
11
  | Class | Kind | Description |
12
- |--------------|-------------|-----------------------------------------------------------------|
12
+ | ------------ | ----------- | --------------------------------------------------------------- |
13
13
  | `.scrollspy` | Component | Marks the nav region for the enhancer; adds no visual styles. |
14
14
  | `.nav-list` | Composition | Vertical list of navigation links. |
15
15
  | `.nav-link` | Component | Navigation link whose active state comes from `[aria-current]`. |
@@ -5,7 +5,7 @@
5
5
  ## Class reference
6
6
 
7
7
  | Class | Kind | Description |
8
- |------------|-----------|----------------------------------------------|
8
+ | ---------- | --------- | -------------------------------------------- |
9
9
  | `.tabs` | Component | Tab strip; pairs with `role="tablist"`. |
10
10
  | `.tab` | Component | One tab trigger; pairs with `role="tab"`. |
11
11
  | `.primary` | Intent | Tints the selected tab's indicator and text. |
@@ -22,6 +22,8 @@ and `actual.full.js` from `dist/`, plus the theme palettes bundle from
22
22
  - [Layout reference](../../demo/templates/layouts.html) - canonical compositions built only with the layout primitives
23
23
  - [Grid density](../../demo/templates/grid.html) - the grid contracts on resizable stages, with the pitfalls called out
24
24
  - [Density](../../demo/templates/density.html) - compact control density
25
+ - [Data grid](../../demo/templates/data-grid.html) - an external data grid component themed with Actual tokens (sort, filter, search, selection)
26
+ - [Combobox](../../demo/templates/combobox.html) - an external combobox themed with Actual tokens (search, tags, autocomplete)
25
27
 
26
28
  ## Sites
27
29
 
@@ -4,10 +4,10 @@
4
4
 
5
5
  ## Class reference
6
6
 
7
- | Class | Kind | Description |
8
- |---------------------------|-----------|---------------------------------------------------------------|
9
- | `.choice-card` | Component | Card-style `<label>` wrapping a native radio or checkbox. |
10
- | `.primary` / `.secondary` | Intent | Intent accent for the selected state (supported on the card). |
7
+ | Class | Kind | Description |
8
+ | ------------------------- | --------- | --------------------------------------------- |
9
+ | `.choice-card` | Component | Card-style `<label>` around a native control. |
10
+ | `.primary` / `.secondary` | Intent | Accent for the selected state. |
11
11
 
12
12
  - Use `.choice-card` on a `<label>` wrapping a native `<input type="radio">` or `<input type="checkbox">`. The input is visually hidden; in browsers without `:has()` it stays visible so selection state never disappears.
13
13
  - Selected items show a primary border, subtle background tint, and a checkmark badge at the top-right corner — round for radio, rounded square for checkbox.
@@ -0,0 +1,87 @@
1
+ # Combobox
2
+
3
+ > A searchable or multi-value combobox is not shipped by the framework — the native `<select>` and `<datalist>` stay the baseline. Theme an external combobox with Actual tokens instead.
4
+
5
+ The `.select` class keeps the native baseline with a CSS chevron, and the optional
6
+ `custom-select` module adds the `appearance: base-select` native picker where the
7
+ browser supports it. Beyond those, apply the framework's judgment from the
8
+ [data grid template](../../demo/templates/data-grid.html) to the problem: when a
9
+ real product needs a JavaScript combobox (searchable select, removable tags,
10
+ autocomplete suggestions), load a dedicated component and bridge its custom
11
+ properties onto Actual's tokens.
12
+
13
+ **Related terms:** combo box, combobox, autocomplete, datalist, searchable select, enhanced select, multiple select, tags, chips, tag input, pill input.
14
+
15
+ ## Theme bridge
16
+
17
+ The [combobox template](../../demo/templates/combobox.html) themes
18
+ [`@lekoala/combobox`](https://github.com/lekoala/combobox) entirely with Actual
19
+ tokens: the control mirrors `.input`, chips re-derive the `.badge` soft recipe,
20
+ and the picker popover follows `--surface-raised` and `--shadow-popout`. No
21
+ adapter, no compatibility layer — a handful of `--cb-*` assignments and shared
22
+ mix tokens.
23
+
24
+ ```html
25
+ <label class="field actual-combobox">
26
+ <span class="field-label">Skills</span>
27
+ <combo-box placeholder="Search or add a skill…">
28
+ <select class="select" name="skills[]" multiple>
29
+ <option value="design" selected>Design</option>
30
+ <option value="css" selected>CSS</option>
31
+ <option value="javascript" selected>JavaScript</option>
32
+ </select>
33
+ </combo-box>
34
+ </label>
35
+ ```
36
+
37
+ The card in the template documents the full token map of this recipe.
38
+
39
+ ## Lightweight pass-through
40
+
41
+ Most of the skin is three one-line token bridges. The visible vocabulary —
42
+ surface, border, radius, focus ring, danger, hover overlay and the `--soft-*`
43
+ mix — stays the Actual one, so light/dark mode, the preset themes and their
44
+ contrast contracts apply to the combobox for free:
45
+
46
+ ```css
47
+ .actual-combobox {
48
+ --cb-bg: var(--surface);
49
+ --cb-color: var(--text);
50
+ --cb-border-color: var(--border);
51
+ --cb-border-radius: var(--radius);
52
+ --cb-focus-color: var(--focus);
53
+ --cb-muted-color: var(--text-muted);
54
+ --cb-error-color: var(--danger);
55
+ --cb-chip-bg: transparent;
56
+ --cb-control-height: var(--control-size);
57
+ --cb-option-min-height: var(--control-size);
58
+ }
59
+
60
+ .actual-combobox .cb-control:focus-within,
61
+ .actual-combobox .cb-text-control:focus {
62
+ outline: 2px solid transparent;
63
+ box-shadow: var(--focus-ring-shadow);
64
+ }
65
+
66
+ .actual-combobox .cb-chip-remove:focus-visible {
67
+ outline: 2px solid transparent;
68
+ box-shadow: 0 0 0 2px var(--focus-ring);
69
+ }
70
+
71
+ .actual-combobox .cb-chip {
72
+ border: var(--border-width) solid
73
+ color-mix(in oklab, var(--surface) var(--soft-border-mix), var(--primary));
74
+ border-radius: var(--radius-full);
75
+ background: color-mix(in oklab, var(--surface) var(--soft-bg-mix), var(--primary));
76
+ color: color-mix(in oklab, var(--primary) var(--soft-fg-mix), var(--text));
77
+ font-size: var(--font-size-xs);
78
+ font-weight: var(--font-weight-strong);
79
+ }
80
+ ```
81
+
82
+ The composite focus ring follows any internal focus, not just the search
83
+ input: focus a chip or its remove × and the control shows the same field ring,
84
+ with the local `:focus-visible` indicator on the chip or its × on top.
85
+
86
+ The same approach works for any widget that exposes a custom-property skin —
87
+ keep the widget's behavior, restyle its tokens through the shared vocabulary.
@@ -7,9 +7,11 @@ the label rests inside the control and floats to the top when the control is
7
7
  focused or filled. It composes the existing `.field` layout and the text
8
8
  controls (`.input`, `.textarea`, `.select`) with zero JavaScript.
9
9
 
10
- The cell holds the control and its label only. Help and error messages stay in
11
- the surrounding `.field`, otherwise the resting label centers on the whole
12
- field instead of the control.
10
+ The cell holds exactly one control and its label, with the control before the
11
+ label. Label placement is linked through the general sibling combinator, so an
12
+ injected node between the two (a password manager, an extension wrapper) is
13
+ tolerated. Help and error messages stay in the surrounding `.field`, otherwise
14
+ the resting label centers on the whole field instead of the control.
13
15
 
14
16
  ```html demo
15
17
  <div class="field">