actual-css 0.2.0 → 0.3.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 (214) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +24 -9
  3. package/dist/actual-themes.min.css +1 -0
  4. package/dist/actual.css +1244 -915
  5. package/dist/actual.js +1 -3
  6. package/dist/actual.min.css +1 -1
  7. package/dist/optional.css +1048 -0
  8. package/dist/optional.min.css +1 -0
  9. package/docs/design-notes/browser-support.md +94 -14
  10. package/docs/design-notes/cascade-layer.md +1 -1
  11. package/docs/design-notes/enhancement-contract.md +11 -14
  12. package/docs/design-notes/forced-colors.md +105 -0
  13. package/docs/design-notes/naming.md +2 -1
  14. package/docs/design-notes/platform-alignment.md +492 -0
  15. package/docs/design-notes/references.md +8 -0
  16. package/docs/design-notes/widget-primitives.md +37 -1
  17. package/docs/navigation.json +135 -0
  18. package/docs/pages/components/accordion.md +80 -0
  19. package/docs/pages/components/alert.md +203 -0
  20. package/docs/pages/components/aura.md +35 -0
  21. package/docs/pages/components/avatar.md +95 -0
  22. package/docs/pages/components/badge.md +102 -0
  23. package/docs/pages/components/breadcrumb.md +19 -0
  24. package/docs/pages/components/button.md +205 -0
  25. package/docs/pages/components/card.md +183 -0
  26. package/docs/pages/components/chat.md +50 -0
  27. package/docs/pages/components/dialog.md +367 -0
  28. package/docs/pages/components/drawer.md +113 -0
  29. package/docs/pages/components/fab.md +118 -0
  30. package/docs/pages/components/key.md +33 -0
  31. package/docs/pages/components/meter.md +23 -0
  32. package/docs/pages/components/navbar.md +92 -0
  33. package/docs/pages/components/pagination.md +55 -0
  34. package/docs/pages/components/progress.md +29 -0
  35. package/docs/pages/components/skeleton.md +38 -0
  36. package/docs/pages/components/spinner.md +93 -0
  37. package/docs/pages/components/table.md +102 -0
  38. package/docs/pages/enhancements/flyout.md +391 -0
  39. package/docs/pages/enhancements/overview.md +36 -0
  40. package/docs/pages/enhancements/scrollspy.md +71 -0
  41. package/docs/pages/enhancements/status-bar.md +72 -0
  42. package/docs/pages/enhancements/tabs.md +80 -0
  43. package/docs/pages/enhancements/tooltip.md +130 -0
  44. package/docs/pages/examples/overview.md +41 -0
  45. package/docs/pages/forms/choice-cards.md +102 -0
  46. package/docs/pages/forms/controls.md +32 -0
  47. package/docs/pages/forms/detached-actions.md +59 -0
  48. package/docs/pages/forms/floating-field.md +88 -0
  49. package/docs/pages/forms/form-actions.md +56 -0
  50. package/docs/pages/forms/input-policy.md +91 -0
  51. package/docs/pages/forms/joined-controls.md +37 -0
  52. package/docs/pages/forms/labels.md +42 -0
  53. package/docs/pages/forms/otp.md +50 -0
  54. package/docs/pages/forms/overview.md +188 -0
  55. package/docs/pages/forms/password.md +40 -0
  56. package/docs/pages/forms/range.md +17 -0
  57. package/docs/pages/forms/states-and-sizes.md +321 -0
  58. package/docs/pages/forms/sticky-actions.md +187 -0
  59. package/docs/pages/forms/switch.md +31 -0
  60. package/docs/pages/forms/validation.md +241 -0
  61. package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
  62. package/docs/pages/foundations/theming.md +92 -0
  63. package/docs/pages/foundations/tokens.md +421 -0
  64. package/docs/{typography.md → pages/foundations/typography.md} +27 -9
  65. package/docs/pages/guides/bootstrap.md +438 -0
  66. package/docs/pages/guides/introduction.md +157 -0
  67. package/docs/pages/guides/optional-components.md +33 -0
  68. package/docs/pages/guides/progressive-enhancement.md +686 -0
  69. package/docs/pages/guides/tailwind.md +455 -0
  70. package/docs/pages/layout/app-shell.md +25 -0
  71. package/docs/pages/layout/center.md +29 -0
  72. package/docs/pages/layout/cluster.md +57 -0
  73. package/docs/pages/layout/frame.md +30 -0
  74. package/docs/pages/layout/grid.md +142 -0
  75. package/docs/pages/layout/list.md +41 -0
  76. package/docs/pages/layout/media.md +21 -0
  77. package/docs/pages/layout/overview.md +37 -0
  78. package/docs/pages/layout/scroll-snap.md +54 -0
  79. package/docs/pages/layout/sidebar-layout.md +27 -0
  80. package/docs/pages/layout/stack.md +18 -0
  81. package/docs/pages/layout/switcher.md +36 -0
  82. package/docs/pages/layout/topbar.md +23 -0
  83. package/docs/pages/patterns/actions.md +52 -0
  84. package/docs/pages/patterns/code-block.md +36 -0
  85. package/docs/pages/patterns/exclusive-accordion.md +16 -0
  86. package/docs/pages/patterns/hierarchical-nav.md +26 -0
  87. package/docs/pages/patterns/icon-input.md +25 -0
  88. package/docs/pages/patterns/intent-nesting.md +3 -0
  89. package/docs/pages/patterns/navigation-list.md +235 -0
  90. package/docs/pages/patterns/overview.md +58 -0
  91. package/docs/pages/patterns/structured-lists.md +47 -0
  92. package/docs/pages/utilities/accessibility.md +34 -0
  93. package/docs/pages/utilities/flex.md +105 -0
  94. package/docs/pages/utilities/links.md +18 -0
  95. package/docs/pages/utilities/list.md +31 -0
  96. package/docs/pages/utilities/overflow.md +43 -0
  97. package/docs/pages/utilities/overview.md +18 -0
  98. package/docs/pages/utilities/shape.md +25 -0
  99. package/docs/pages/utilities/sizing-wrapping.md +115 -0
  100. package/docs/pages/utilities/spacing.md +79 -0
  101. package/docs/pages/utilities/text.md +43 -0
  102. package/llms.txt +4 -4
  103. package/package.json +20 -12
  104. package/src/css/actual.css +12 -1
  105. package/src/css/base.css +3 -5
  106. package/src/css/components/accordion.css +18 -30
  107. package/src/css/components/actions.css +4 -1
  108. package/src/css/components/alert.css +126 -99
  109. package/src/css/components/avatar.css +16 -10
  110. package/src/css/components/badge.css +55 -35
  111. package/src/css/components/breadcrumb.css +7 -15
  112. package/src/css/components/busy.css +6 -0
  113. package/src/css/components/button.css +78 -32
  114. package/src/css/components/card.css +17 -37
  115. package/src/css/components/drawer.css +30 -13
  116. package/src/css/components/flyout.css +39 -109
  117. package/src/css/components/index.css +1 -0
  118. package/src/css/components/join.css +14 -2
  119. package/src/css/components/key.css +2 -0
  120. package/src/css/components/menu.css +125 -0
  121. package/src/css/components/meter.css +0 -23
  122. package/src/css/components/modal.css +162 -7
  123. package/src/css/components/navbar.css +17 -18
  124. package/src/css/components/overline.css +0 -7
  125. package/src/css/components/pagination.css +1 -1
  126. package/src/css/components/progress.css +8 -26
  127. package/src/css/components/skeleton.css +7 -0
  128. package/src/css/components/spinner.css +6 -7
  129. package/src/css/components/status-bar.css +15 -24
  130. package/src/css/components/surface.css +2 -8
  131. package/src/css/components/tab.css +19 -48
  132. package/src/css/components/table.css +7 -5
  133. package/src/css/components/tooltip.css +14 -7
  134. package/src/css/focus.css +14 -38
  135. package/src/css/forms/choice-card.css +13 -14
  136. package/src/css/forms/choice.css +21 -27
  137. package/src/css/forms/control.css +16 -17
  138. package/src/css/forms/custom-select.css +9 -11
  139. package/src/css/forms/form-actions.css +14 -3
  140. package/src/css/forms/form.css +7 -4
  141. package/src/css/forms/index.css +4 -4
  142. package/src/css/forms/input-icon.css +30 -12
  143. package/src/css/forms/native.css +50 -11
  144. package/src/css/forms/range.css +17 -9
  145. package/src/css/forms/select.css +8 -8
  146. package/src/css/forms/switch.css +14 -12
  147. package/src/css/forms/validation.css +32 -5
  148. package/src/css/grid.css +19 -18
  149. package/src/css/intents.css +2 -2
  150. package/src/css/layout.css +29 -1
  151. package/src/css/optional/aura.css +93 -0
  152. package/src/css/optional/chat.css +105 -0
  153. package/src/css/optional/fab.css +104 -0
  154. package/src/css/optional/floating-field.css +87 -0
  155. package/src/css/optional/index.css +5 -0
  156. package/src/css/optional/layout-extra.css +7 -4
  157. package/src/css/optional/otp.css +115 -0
  158. package/src/css/optional/scroll-snap.css +6 -0
  159. package/src/css/optional/scroller.css +13 -7
  160. package/src/css/optional/typography-fluid.css +5 -0
  161. package/src/css/optional/utilities-extra.css +17 -2
  162. package/src/css/prose.css +18 -8
  163. package/src/css/reset.css +0 -10
  164. package/src/css/theme.css +21 -5
  165. package/src/css/themes/cyberpunk.css +1 -1
  166. package/src/css/themes/dim.css +3 -3
  167. package/src/css/themes/edge.css +8 -10
  168. package/src/css/themes/index.css +3 -3
  169. package/src/css/themes/{dark.css → indigo.css} +5 -4
  170. package/src/css/themes/neon.css +5 -5
  171. package/src/css/themes/square.css +0 -3
  172. package/src/css/tokens.css +74 -20
  173. package/src/css/utilities.css +8 -10
  174. package/src/css/variants.css +37 -65
  175. package/src/js/command.js +1 -3
  176. package/src/js/context-menu.js +67 -35
  177. package/src/js/dialog.js +68 -79
  178. package/src/js/dismiss.js +15 -0
  179. package/src/js/enhance.js +54 -23
  180. package/src/js/enhancement-loader.js +301 -0
  181. package/src/js/events.js +3 -0
  182. package/src/js/filter.js +3 -3
  183. package/src/js/floating.js +101 -131
  184. package/src/js/flyout.js +104 -87
  185. package/src/js/focus-group.js +116 -0
  186. package/src/js/focus.js +6 -1
  187. package/src/js/index.js +4 -2
  188. package/src/js/input.js +1 -1
  189. package/src/js/keys.js +27 -0
  190. package/src/js/mask.js +7 -6
  191. package/src/js/menu.js +87 -34
  192. package/src/js/parse-config.js +47 -0
  193. package/src/js/password.js +9 -1
  194. package/src/js/scrollspy.js +12 -4
  195. package/src/js/selectors.js +0 -7
  196. package/src/js/status.js +3 -1
  197. package/src/js/surface.js +185 -136
  198. package/src/js/tab.js +36 -53
  199. package/src/js/tooltip.js +53 -31
  200. package/src/js/validation.js +34 -8
  201. package/dist/actual.js.map +0 -31
  202. package/docs/README.md +0 -28
  203. package/docs/components.md +0 -860
  204. package/docs/design-notes/previous-work.md +0 -5
  205. package/docs/forms.md +0 -1265
  206. package/docs/javascript.md +0 -496
  207. package/docs/layout.md +0 -480
  208. package/docs/patterns.md +0 -504
  209. package/docs/reserved.md +0 -7
  210. package/docs/tokens.md +0 -455
  211. package/docs/ui.md +0 -929
  212. package/docs/utilities.md +0 -384
  213. package/src/css/dialog-fallback.css +0 -56
  214. package/src/js/dialog-fallback.js +0 -163
@@ -0,0 +1,455 @@
1
+ # Migrating from Tailwind CSS to Actual CSS
2
+
3
+ This guide primarily targets Tailwind CSS v4. The same migration principles apply to Tailwind v3 projects.
4
+
5
+ Tailwind and Actual CSS solve styling at different abstraction levels, so this should **not** be approached as a class-by-class conversion.
6
+
7
+ The useful migration model is:
8
+
9
+ **repeated utility clusters → Actual components**
10
+ **layout utility clusters → Actual layout primitives**
11
+ **design tokens → Actual theme tokens**
12
+ **one-off utility combinations → small project CSS**
13
+
14
+ If you finish the migration with a new `.mt-4`, `.flex`, `.bg-primary`, and `md:*` API built around Actual, you have recreated the framework you were trying to remove.
15
+
16
+ ## Before you start: avoid class collisions
17
+
18
+ Tailwind and Actual can temporarily coexist, but some short class names overlap.
19
+
20
+ Examples include layout and flex-related names such as `.grid`, `.grow`, and `.items-center`.
21
+
22
+ For a staged migration, use cascade layers, controlled import order, or a project-side Actual prefix transform where necessary.
23
+
24
+ The layered import is the cleanest way to keep both stylesheets during the
25
+ migration:
26
+
27
+ ```css
28
+ /* Migration setup — Actual rules sit in @layer actual */
29
+ @import "tailwind.css"; /* your compiled Tailwind output */
30
+ @import "actual-css/css/layer";
31
+ /* Unlayered project overrides stay on top */
32
+ @import "app.css";
33
+ ```
34
+
35
+ `actual.layer.css` wraps every Actual rule in a single `@layer actual`, so
36
+ unlayered Tailwind output and project CSS keep precedence while the migration
37
+ runs. See [Cascade layer strategy](https://github.com/lekoala/actual-css/blob/master/docs/design-notes/cascade-layer.md) for the
38
+ limitations of the approach.
39
+
40
+ Do not assume that loading both complete stylesheets is automatically safe.
41
+
42
+ ## Start with components, not utilities
43
+
44
+ A Tailwind button may look like this:
45
+
46
+ ```html
47
+ <button
48
+ class="
49
+ inline-flex items-center gap-2
50
+ rounded-md
51
+ bg-blue-600 px-4 py-2
52
+ font-medium text-white
53
+ hover:bg-blue-700
54
+ focus:outline-none focus:ring-2
55
+ "
56
+ >
57
+ Save
58
+ </button>
59
+ ```
60
+
61
+ With Actual:
62
+
63
+ ```html
64
+ <button class="btn primary">
65
+ Save
66
+ </button>
67
+ ```
68
+
69
+ The border, spacing, typography, hover state, focus treatment, disabled state, and theme behavior belong to the component.
70
+
71
+ The intent remains visible in the markup without re-describing its CSS implementation.
72
+
73
+ The same principle applies to badges, alerts, cards, form controls, pagination, tabs, dialogs, and other Actual components.
74
+
75
+ ## Translate layout relationships
76
+
77
+ ### Vertical spacing
78
+
79
+ Tailwind:
80
+
81
+ ```html
82
+ <div class="flex flex-col gap-4">
83
+ ...
84
+ </div>
85
+ ```
86
+
87
+ Actual:
88
+
89
+ ```html
90
+ <div class="stack">
91
+ ...
92
+ </div>
93
+ ```
94
+
95
+ ### Inline actions
96
+
97
+ Tailwind:
98
+
99
+ ```html
100
+ <div class="flex flex-wrap items-center gap-3">
101
+ ...
102
+ </div>
103
+ ```
104
+
105
+ Actual:
106
+
107
+ ```html
108
+ <div class="cluster">
109
+ ...
110
+ </div>
111
+ ```
112
+
113
+ ### Fixed column count
114
+
115
+ Tailwind:
116
+
117
+ ```html
118
+ <div class="grid grid-cols-3 gap-6">
119
+ ...
120
+ </div>
121
+ ```
122
+
123
+ Actual:
124
+
125
+ ```html
126
+ <div class="grid-3">
127
+ ...
128
+ </div>
129
+ ```
130
+
131
+ If the grid should respond to its container:
132
+
133
+ ```html
134
+ <div class="container-query">
135
+ <div class="grid-3">
136
+ ...
137
+ </div>
138
+ </div>
139
+ ```
140
+
141
+ ### Intrinsic responsive grid
142
+
143
+ Instead of:
144
+
145
+ ```html
146
+ <div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
147
+ ```
148
+
149
+ consider whether the real requirement is simply “create another column whenever there is enough room”:
150
+
151
+ ```html
152
+ <div class="grid" style="--grid-min: 16rem">
153
+ ```
154
+
155
+ This removes viewport breakpoint choreography entirely.
156
+
157
+ ## Prefer intrinsic behavior over translating breakpoints
158
+
159
+ Tailwind allows almost every utility to be changed independently at a breakpoint:
160
+
161
+ ```html
162
+ <div class="flex flex-col gap-4 md:flex-row md:items-center xl:gap-8">
163
+ ```
164
+
165
+ There is intentionally no equivalent Actual syntax such as:
166
+
167
+ ```text
168
+ md:cluster xl:gap-lg
169
+ ```
170
+
171
+ First ask what the layout is supposed to do.
172
+
173
+ If the requirement is:
174
+
175
+ > Show these items horizontally when there is enough room, otherwise stack them.
176
+
177
+ use a layout primitive such as `.switcher`.
178
+
179
+ If the requirement truly is:
180
+
181
+ > At exactly this application breakpoint, change these particular properties.
182
+
183
+ write project CSS:
184
+
185
+ ```html
186
+ <div class="account-header">
187
+ ...
188
+ </div>
189
+ ```
190
+
191
+ ```css
192
+ .account-header {
193
+ display: grid;
194
+ gap: var(--space-40);
195
+ }
196
+
197
+ @media (width >= 48rem) {
198
+ .account-header {
199
+ grid-template-columns: 1fr auto;
200
+ align-items: center;
201
+ }
202
+ }
203
+ ```
204
+
205
+ Actual does not prohibit media queries. It simply does not encode every media query/property combination into the class API.
206
+
207
+ ## Utility translation guide
208
+
209
+ | Tailwind usage | Actual approach |
210
+ |--------------------------------------|---------------------------------------------------|
211
+ | `flex flex-col gap-*` | `.stack` |
212
+ | `flex flex-wrap items-center gap-*` | `.cluster` |
213
+ | `grid grid-cols-*` | `.grid`, `.grid-2`, `.grid-3`, etc. |
214
+ | responsive row → column | `.switcher` when intrinsic behavior fits |
215
+ | `max-w-*` for readable text | `.measure` where appropriate |
216
+ | common visual component bundle | Actual component |
217
+ | component colors | intents such as `.primary`, `.danger`, `.success` |
218
+ | repeated layout spacing | `--gap` / layout hooks |
219
+ | small common corrections | Actual utilities |
220
+ | breakpoint-prefixed utilities | intrinsic layout, container query, or project CSS |
221
+ | arbitrary values | custom property or project CSS |
222
+ | arbitrary selectors | project CSS |
223
+ | `group-*` / `peer-*` variants | semantic state + project CSS |
224
+ | `data-*` / `aria-*` variants | component state or project CSS |
225
+ | decorative color utilities | theme token or project CSS |
226
+ | transforms/effects/complex animation | project CSS |
227
+
228
+ ## Do not translate Tailwind's full spacing API
229
+
230
+ Tailwind makes it convenient to express:
231
+
232
+ ```html
233
+ <div class="mt-3 mb-8 px-5 md:px-8">
234
+ ```
235
+
236
+ Actual deliberately has a much smaller spacing utility surface.
237
+
238
+ Use layout primitives to create rhythm between siblings:
239
+
240
+ ```html
241
+ <section class="stack">
242
+ ...
243
+ </section>
244
+ ```
245
+
246
+ Use component padding when the space belongs to the component.
247
+
248
+ Use a small semantic project rule when the spacing genuinely belongs to an application-specific structure:
249
+
250
+ ```css
251
+ .account-section {
252
+ padding-inline: var(--space-40);
253
+ margin-block-end: var(--space-60);
254
+ }
255
+ ```
256
+
257
+ The goal is not zero custom CSS. The goal is CSS attached to meaningful structures instead of reconstructing every declaration in HTML.
258
+
259
+ > **Need something more specific?**
260
+ >
261
+ > 1. Tune the component or layout primitive with a public custom property.
262
+ > 2. Compose an Actual layout primitive.
263
+ > 3. Add a project class for application-specific CSS.
264
+ > 4. Only reach for an optional utility when the rule is genuinely generic.
265
+
266
+ Actual deliberately keeps its utility surface small and grows it only for needs
267
+ that recur across real migrations — a one-off is project CSS, not a new
268
+ framework class.
269
+
270
+ ## Arbitrary values move back into CSS
271
+
272
+ Tailwind can express one-off values directly:
273
+
274
+ ```html
275
+ <div class="grid-cols-[24rem_2.5rem_minmax(0,1fr)]">
276
+ ```
277
+
278
+ or:
279
+
280
+ ```html
281
+ <div class="top-[117px]">
282
+ ```
283
+
284
+ Actual has no equivalent arbitrary-value grammar.
285
+
286
+ Use a public layout hook when one exists:
287
+
288
+ ```html
289
+ <div class="grid report-layout">
290
+ ```
291
+
292
+ ```css
293
+ .report-layout {
294
+ --grid-columns: 24rem 2.5rem minmax(0, 1fr);
295
+ }
296
+ ```
297
+
298
+ Otherwise write the declaration normally.
299
+
300
+ This is one of the largest mechanical differences for Tailwind-heavy applications.
301
+
302
+ ## State variants move into component behavior or CSS
303
+
304
+ Tailwind can keep highly specific state rules in markup:
305
+
306
+ ```html
307
+ <button
308
+ class="
309
+ bg-neutral-100
310
+ hover:bg-neutral-200
311
+ aria-pressed:bg-blue-600
312
+ aria-pressed:text-white
313
+ disabled:opacity-50
314
+ "
315
+ >
316
+ ```
317
+
318
+ For an Actual component, common interactive states should already be part of the component contract:
319
+
320
+ ```html
321
+ <button class="btn primary" aria-pressed="true">
322
+ ```
323
+
324
+ For application-specific state styling, keep the semantic attribute and style it directly:
325
+
326
+ ```css
327
+ .view-toggle[aria-pressed="true"] {
328
+ /* project-specific state */
329
+ }
330
+ ```
331
+
332
+ The same applies to Tailwind's `group-*`, `peer-*`, arbitrary selector, and complex `data-*` variants.
333
+
334
+ Do not invent an Actual variant grammar to replace them.
335
+
336
+ ## Colors and dark mode
337
+
338
+ Tailwind makes low-level color selection easy:
339
+
340
+ ```html
341
+ <div class="bg-slate-950 text-slate-100 border-slate-800">
342
+ ```
343
+
344
+ Actual's intent classes are not a general-purpose color palette.
345
+
346
+ Use intents where color has component meaning:
347
+
348
+ ```html
349
+ <div class="alert danger">...</div>
350
+ ```
351
+
352
+ For application surfaces, define theme-aware project tokens instead:
353
+
354
+ ```css
355
+ :root {
356
+ --dashboard-surface: ...;
357
+ --dashboard-border: ...;
358
+ }
359
+
360
+ .dashboard-panel {
361
+ background: var(--dashboard-surface);
362
+ border-color: var(--dashboard-border);
363
+ }
364
+ ```
365
+
366
+ Actual theme tokens should handle shared theme behavior. Local CSS remains appropriate for visual concepts that are specific to the application.
367
+
368
+ This is particularly important when migrating a Tailwind application with a large custom color palette.
369
+
370
+ ## Forms
371
+
372
+ Tailwind applications often construct form controls from utility combinations or use an additional forms plugin.
373
+
374
+ Actual provides explicit form components:
375
+
376
+ ```html
377
+ <label class="field">
378
+ <span class="field-label">Email</span>
379
+ <input class="input" type="email">
380
+ <span class="field-help">We'll only use this for notifications.</span>
381
+ </label>
382
+ ```
383
+
384
+ A utility-heavy form is therefore usually easier to migrate than a utility-heavy marketing layout.
385
+
386
+ ## Third-party Tailwind components
387
+
388
+ This can be a significant migration cost.
389
+
390
+ A React, Vue, Svelte, or template component containing dozens of Tailwind classes does not become framework-independent merely because those classes are hidden behind a component abstraction.
391
+
392
+ For each component:
393
+
394
+ 1. identify whether an Actual component already provides the UI primitive;
395
+ 2. replace the utility bundle with that component when possible;
396
+ 3. preserve application-specific styling in a local component class;
397
+ 4. keep existing application behavior unless an Actual enhancement can replace it cleanly.
398
+
399
+ Third-party component libraries authored specifically around Tailwind usually require restyling rather than automated class substitution.
400
+
401
+ ## Build pipeline
402
+
403
+ Once the last Tailwind classes are gone, the Tailwind compilation and source scanning pipeline is no longer required for Actual itself.
404
+
405
+ Actual can be imported as regular CSS, with modular imports when desired.
406
+
407
+ Do not remove Tailwind from the build until migrated screens no longer depend on generated utilities.
408
+
409
+ ## Where migration is genuinely harder
410
+
411
+ | Existing Tailwind usage | Migration cost |
412
+ |----------------------------------------------------|----------------|
413
+ | buttons, badges, alerts, forms | low |
414
+ | repeated card/panel patterns | low |
415
+ | basic flex/grid composition | low to medium |
416
+ | intrinsic responsive layouts | low to medium |
417
+ | breakpoint-heavy layouts | medium to high |
418
+ | extensive arbitrary values | high |
419
+ | `group`, `peer`, attribute, and arbitrary variants | high |
420
+ | bespoke marketing/art-direction layouts | high |
421
+ | large application-specific color utility palette | high |
422
+ | Tailwind-native third-party component libraries | high |
423
+
424
+ This is not accidental.
425
+
426
+ Actual gives you components and layout primitives but deliberately stops before becoming a complete vocabulary for expressing arbitrary CSS from HTML.
427
+
428
+ ## Recommended migration order
429
+
430
+ 1. Establish safe coexistence while both stylesheets are present.
431
+ 2. Find repeated Tailwind class bundles that already represent recognizable UI components.
432
+ 3. Replace buttons, badges, alerts, cards, and forms with Actual components.
433
+ 4. Convert simple flex layouts to `.stack` and `.cluster`.
434
+ 5. Convert repeated grids to Actual grid primitives.
435
+ 6. Replace useful breakpoint choreography with intrinsic layouts or container queries.
436
+ 7. Move remaining arbitrary values and state variants into small project classes.
437
+ 8. Migrate application theme values to Actual tokens and project tokens.
438
+ 9. Remove unused Tailwind-dependent components.
439
+ 10. Remove Tailwind and its build integration.
440
+
441
+ ## When Tailwind may still be the better fit
442
+
443
+ Actual is not intended to make every Tailwind workflow equally convenient.
444
+
445
+ If your application deliberately wants:
446
+
447
+ * every styling decision colocated in markup;
448
+ * arbitrary per-element visual values;
449
+ * extensive responsive changes to individual properties;
450
+ * complex `group`, `peer`, and selector-driven state styling;
451
+ * highly bespoke visual composition with few repeated UI components;
452
+
453
+ then Tailwind's utility and variant model may remain a better fit.
454
+
455
+ If the application is mostly composed from recurring UI components, forms, application layouts, and a stable theme, Actual can substantially reduce the amount of styling information carried by the markup.
@@ -0,0 +1,25 @@
1
+ # App Shell
2
+
3
+ Document landmarks for top and bottom regions, composed with layout primitives.
4
+
5
+ Header and footer are document landmarks, not required layout classes.
6
+
7
+ Use semantic elements by default.
8
+
9
+ ```html demo
10
+ <body class="app-shell">
11
+ <header>Actual CSS</header>
12
+ <main class="grow">Main content</main>
13
+ <footer>Footer links</footer>
14
+ </body>
15
+ ```
16
+
17
+ ```css
18
+ .app-shell {
19
+ min-block-size: 100vh;
20
+ display: flex;
21
+ flex-direction: column;
22
+ }
23
+ ```
24
+
25
+ Sticky header/footer behavior should be opt-in and documented only if it becomes part of the shipped layout API.
@@ -0,0 +1,29 @@
1
+ # Center
2
+
3
+ Constrain readable content and center it in the viewport, with width and padding tunable per instance.
4
+
5
+ ```html demo
6
+ <main class="center stack">
7
+ <header class="prose">
8
+ <h1>Documentation</h1>
9
+ <p>Guides and API notes for Actual CSS.</p>
10
+ </header>
11
+ <section class="card">
12
+ <h2>Getting started</h2>
13
+ <p>Install the stylesheet and use semantic HTML.</p>
14
+ </section>
15
+ </main>
16
+ ```
17
+
18
+ Tune width and side padding with local variables.
19
+
20
+ ```css
21
+ .docs-page {
22
+ --center-size: 48rem;
23
+ --center-pad: var(--space-40);
24
+ }
25
+ ```
26
+
27
+ `.center` intentionally uses `box-sizing: content-box`. The max inline size is
28
+ the content measure, while inline padding is added outside that measure. This is
29
+ deliberate even though the global reset uses `border-box`.
@@ -0,0 +1,57 @@
1
+ # Cluster
2
+
3
+ Inline groups that wrap naturally, useful for action rows, tags, and toolbars.
4
+
5
+ ```html demo
6
+ <div class="cluster">
7
+ <button class="btn primary" type="button">Save</button>
8
+ <button class="btn outline" type="button">Cancel</button>
9
+ <a href="#">Read docs</a>
10
+ </div>
11
+ ```
12
+
13
+ Use cluster for action rows, tags, toolbar sections, metadata, and compact navigation.
14
+
15
+ Like `.stack`, cluster owns its children's spacing: direct-child margins are
16
+ reset, so spacing between items always comes from `--gap`.
17
+
18
+ ## CSS hooks
19
+
20
+ - `--cluster-justify` — main-axis distribution (`justify-content`).
21
+ - `--cluster-align` — cross-axis alignment (`align-items`).
22
+ - `--cluster-wrap` — wrapping behavior (`flex-wrap`); set to `nowrap` to force a single row.
23
+ - `--gap` — space between items.
24
+
25
+ ## Split / spread
26
+
27
+ For split/spread layouts — two items apart, at opposite ends, or "one left / one
28
+ right" — use `.cluster` with `--cluster-justify: space-between`. There is no
29
+ separate `.split` or `.spread` primitive; this is the same relationship.
30
+
31
+ ```html demo
32
+ <div class="cluster" style="--cluster-justify: space-between">
33
+ <h2>Results</h2>
34
+ <button class="btn primary" type="button">New search</button>
35
+ </div>
36
+ ```
37
+
38
+ To align a row to its top edge instead of centering it — useful when one item
39
+ wraps to several lines — set `--cluster-align`.
40
+
41
+ ```css
42
+ .filters {
43
+ --cluster-align: start;
44
+ --cluster-justify: space-between;
45
+ }
46
+ ```
47
+
48
+ The optional utility layer ships `.justify-content-start`, `.justify-content-center`,
49
+ `.justify-content-end` and `.justify-content-space-between`, which set
50
+ `--cluster-justify` for you. See the utilities page.
51
+
52
+ ## Controls inside a wrapping cluster
53
+
54
+ A form control (`--control-size`, full width) inside a **wrapping** cluster claims
55
+ the full line and pushes every sibling to its own row. To keep a row of controls
56
+ under one label, set `--cluster-wrap: nowrap` and give the controls
57
+ `min-inline-size: 0` (and `flex: 1 1 0%` to share the row evenly).
@@ -0,0 +1,30 @@
1
+ # Frame
2
+
3
+ Media container that holds a stable aspect ratio for images, video, or embeds.
4
+
5
+ ```html demo
6
+ <figure class="frame">
7
+ <img src="https://picsum.photos/seed/actual-css-frame/1600/900" alt="Preview placeholder" width="1600" height="900" />
8
+ </figure>
9
+ ```
10
+
11
+ ```css
12
+ .frame {
13
+ aspect-ratio: var(--frame-ratio, 16 / 9);
14
+ overflow: hidden;
15
+ }
16
+
17
+ .frame > :where(img, video, iframe) {
18
+ inline-size: 100%;
19
+ block-size: 100%;
20
+ object-fit: cover;
21
+ }
22
+ ```
23
+
24
+ Use local variables for common ratios.
25
+
26
+ ```css
27
+ .avatar-preview {
28
+ --frame-ratio: 1;
29
+ }
30
+ ```