@csszyx/mcp-server 0.9.9 → 0.10.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.
- package/dist/index.mjs +10 -6
- package/llms-full.txt +281 -182
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -65,12 +65,14 @@ Key csszyx rules:
|
|
|
65
65
|
- Colors are strings: { bg: 'blue-500' } \u2192 bg-blue-500
|
|
66
66
|
- Color + opacity is an object: { bg: { color: 'blue-500', op: 50 } } \u2192 bg-blue-500/50
|
|
67
67
|
- Variants nest: { hover: { bg: 'blue-700' } } \u2192 hover:bg-blue-700
|
|
68
|
-
-
|
|
68
|
+
- ONE way per property \u2014 single-property props use the canonical key with a value, never a boolean alias. display/position/visibility/isolation/textTransform/fontStyle/fontSmoothing/decoration: { display: 'flex' } \u2192 flex, { position: 'absolute' } \u2192 absolute, { fontStyle: 'italic' } \u2192 italic, { decoration: 'underline' } \u2192 underline, { fontSmoothing: 'grayscale' } \u2192 antialiased. Boolean aliases like { flex: true }/{ italic: true } were REMOVED and emit nothing.
|
|
69
69
|
- Fractions stay native: { w: '1/2' } \u2192 w-1/2
|
|
70
70
|
- Arbitrary values: { p: '5px' } \u2192 p-[5px]
|
|
71
71
|
- CSS variables: { p: '--my-var' } \u2192 p-(--my-var)
|
|
72
72
|
- Scope variants: { group: { hover: { bg: 'blue-700' } } } \u2192 group-hover:bg-blue-700 (also peer)
|
|
73
|
-
- Conditional/feature variants: { has: { checked: { ... } } } \u2192 has-[:checked]:\u2026, { supports: { 'display:grid': { ... } } } \u2192 supports-[display:grid]:\u2026 (also not/data/aria)
|
|
73
|
+
- Conditional/feature variants: { has: { checked: { ... } } } \u2192 has-[:checked]:\u2026, { supports: { 'display:grid': { ... } } } \u2192 supports-[display:grid]:\u2026 (also not/data/aria)
|
|
74
|
+
- Type-safe keys: the sz prop type is CLOSED \u2014 an unknown/typo key (e.g. { bgColor: 'red' }, canonical is { bg: 'red' }) is a TypeScript error, so a literal sz object is caught by tsc/CI. To force a brand-new Tailwind utility csszyx has no key for yet, opt out with // @ts-expect-error on that line (the runtime still emits the class). Arbitrary variants (@container, min-[320px], [&>span]) are allowed by pattern.
|
|
75
|
+
- Custom breakpoints are typed from CSS: define it once in Tailwind @theme (e.g. @theme { --breakpoint-tablet: 40rem }) and csszyx auto-generates the type so { tablet: { ... } } type-checks \u2014 no manual declaration.`
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
]
|
|
@@ -96,7 +98,7 @@ Please:
|
|
|
96
98
|
|
|
97
99
|
Key csszyx syntax:
|
|
98
100
|
- <div sz={{ p: 4, bg: 'blue-500', hover: { bg: 'blue-700' } }} />
|
|
99
|
-
- <div sz={{
|
|
101
|
+
- <div sz={{ display: 'flex', items: 'center', gap: 4 }} />
|
|
100
102
|
- <div sz={{ md: { gridCols: 3 }, gridCols: 1, gap: 6 }} />
|
|
101
103
|
- <div sz={{ dark: { bg: 'gray-900', color: 'white' } }} />
|
|
102
104
|
- <div sz={{ bg: { color: 'blue-500', op: 50 }, w: '1/2' }} /> (color opacity + fraction)
|
|
@@ -356,11 +358,13 @@ const EXAMPLES = {
|
|
|
356
358
|
h: ["{ h: 16 }", "{ h: 'screen' }"],
|
|
357
359
|
text: ["{ text: 'lg' }", "{ text: '2xl' }"],
|
|
358
360
|
color: ["{ color: 'white' }", "{ color: 'slate-500' }"],
|
|
359
|
-
|
|
361
|
+
weight: ["{ weight: 'bold' }", "{ weight: 700 }"],
|
|
360
362
|
fontFamily: ["{ fontFamily: 'sans' }", "{ fontFamily: 'mono' }"],
|
|
361
|
-
|
|
363
|
+
display: ["{ display: 'flex' }", "{ display: 'none' }"],
|
|
364
|
+
position: ["{ position: 'absolute' }", "{ position: 'relative' }"],
|
|
365
|
+
flex: ["{ flex: 1 }", "{ flex: 'auto' }"],
|
|
362
366
|
flexDir: ["{ flexDir: 'col' }", "{ flexDir: 'row' }"],
|
|
363
|
-
grid: ["{
|
|
367
|
+
grid: ["{ display: 'grid' }"],
|
|
364
368
|
gridCols: ["{ gridCols: 3 }", "{ gridCols: 'none' }"],
|
|
365
369
|
gap: ["{ gap: 4 }"],
|
|
366
370
|
items: ["{ items: 'center' }", "{ items: 'start' }"],
|
package/llms-full.txt
CHANGED
|
@@ -48,20 +48,37 @@ module.exports = {
|
|
|
48
48
|
<div className="flex items-center p-4 bg-blue-500 rounded-lg" />
|
|
49
49
|
|
|
50
50
|
// After (CSSzyx)
|
|
51
|
-
<div sz={{
|
|
51
|
+
<div sz={{ display: 'flex', items: 'center', p: 4, bg: 'blue-500', rounded: 'lg' }} />
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
The compiler transforms `sz` props → Tailwind classes at build time. The browser never sees `sz`.
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### One key per property
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Single-property props use their canonical key with a value — one way, no
|
|
59
|
+
aliases. display/position/visibility/isolation/textTransform/fontStyle/
|
|
60
|
+
fontSmoothing/decoration:
|
|
59
61
|
|
|
60
62
|
```tsx
|
|
61
|
-
<div
|
|
62
|
-
|
|
63
|
+
<div
|
|
64
|
+
sz={{
|
|
65
|
+
display: "flex",
|
|
66
|
+
position: "relative",
|
|
67
|
+
visibility: "hidden",
|
|
68
|
+
fontStyle: "italic",
|
|
69
|
+
}}
|
|
70
|
+
/>
|
|
71
|
+
// → className="flex relative invisible italic"
|
|
63
72
|
```
|
|
64
73
|
|
|
74
|
+
Boolean aliases (`{ flex: true }`, `{ italic: true }`, `{ uppercase: true }`)
|
|
75
|
+
were **removed** — they emit nothing and warn; run `csszyx migrate` to rewrite.
|
|
76
|
+
Each property has exactly one key, so it can never be set twice in one object.
|
|
77
|
+
|
|
78
|
+
Genuinely on/off utilities — composite (`truncate`, `srOnly`), stackable
|
|
79
|
+
font-variant-numeric (`ordinal`, `tabularNums`), default-or-value (`grow`,
|
|
80
|
+
`ring`, `blur`), plugin (`container`, `prose`) — stay boolean.
|
|
81
|
+
|
|
65
82
|
### Arbitrary values
|
|
66
83
|
|
|
67
84
|
```tsx
|
|
@@ -162,7 +179,7 @@ sz={{ group: { card: { data: { active: { color: 'blue-600' } } } } }}
|
|
|
162
179
|
sz={{ group: { aria: { expanded: { color: 'blue-600' } } } }}
|
|
163
180
|
// → className="group-aria-expanded:text-blue-600"
|
|
164
181
|
|
|
165
|
-
sz={{ group: { aria: { 'current=page': {
|
|
182
|
+
sz={{ group: { aria: { 'current=page': { weight: 'bold' } } } }}
|
|
166
183
|
// → className="group-aria-[current=page]:font-bold"
|
|
167
184
|
|
|
168
185
|
// peer-data / peer-aria work the same way
|
|
@@ -195,7 +212,7 @@ sz={{ placeholder: { color: 'gray-400' } }}
|
|
|
195
212
|
### Container queries
|
|
196
213
|
|
|
197
214
|
```tsx
|
|
198
|
-
sz={{ '@container': true, '@md': {
|
|
215
|
+
sz={{ '@container': true, '@md': { display: 'flex' } }}
|
|
199
216
|
// → className="@container @md:flex"
|
|
200
217
|
```
|
|
201
218
|
|
|
@@ -221,7 +238,29 @@ sz={{ '@container': true, '@md': { flex: true } }}
|
|
|
221
238
|
<div className="p-4" sz={{ m: 2 }} /> // Wrong — use sz only
|
|
222
239
|
|
|
223
240
|
// ✅ Correct
|
|
224
|
-
{ p: 4, bg: 'blue-500',
|
|
241
|
+
{ p: 4, bg: 'blue-500', display: 'flex', flexDir: 'col', w: '333px', mt: 4, text: 'lg' }
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Type safety — unknown keys are TypeScript errors
|
|
245
|
+
|
|
246
|
+
The `sz` prop type is **closed**: a key that is not a known sz prop or variant is a
|
|
247
|
+
compile error, so typos and legacy CSS-property names are caught by `tsc` (run
|
|
248
|
+
`tsc --noEmit` in CI to enforce it).
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
{ bgColor: 'red-500' } // ❌ tsc error — unknown key; canonical is { bg: 'red-500' }
|
|
252
|
+
|
|
253
|
+
// Forcing a brand-new Tailwind utility csszyx has no key for yet — opt out explicitly:
|
|
254
|
+
// @ts-expect-error - forward-compat utility not yet in csszyx
|
|
255
|
+
{ someNewUtility: 'x' } // ✅ allowed; the runtime still emits the class
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Arbitrary variants are allowed by pattern: `{ '@container': {…} }`, `{ 'min-[320px]': {…} }`,
|
|
259
|
+
`{ '[&>span]': {…} }`. **Custom breakpoints are typed from your CSS** — define one once in
|
|
260
|
+
Tailwind `@theme` and csszyx auto-generates the type:
|
|
261
|
+
|
|
262
|
+
```css
|
|
263
|
+
@theme { --breakpoint-tablet: 40rem; } /* → { tablet: { p: 6 } } now type-checks */
|
|
225
264
|
```
|
|
226
265
|
|
|
227
266
|
## Full Snippets Reference
|
|
@@ -241,7 +280,7 @@ Simple property-value mappings.
|
|
|
241
280
|
| **Text Color** | `color: white` | `text-white` | `{ color: 'white' }` |
|
|
242
281
|
| **Border Radius** | `border-radius: var(--radius-lg)` | `rounded-lg` | `{ rounded: 'lg' }` |
|
|
243
282
|
| **Box Shadow** | `box-shadow: var(--shadow-xl)` | `shadow-xl` | `{ shadow: 'xl' }` |
|
|
244
|
-
| **Flex Container** | `display: flex` | `flex` | `{
|
|
283
|
+
| **Flex Container** | `display: flex` | `flex` | `{ display: 'flex' }` |
|
|
245
284
|
|
|
246
285
|
## State Modifiers (Hover, Focus)
|
|
247
286
|
|
|
@@ -258,11 +297,11 @@ Handling pseudo-classes using nested objects or string prefixes.
|
|
|
258
297
|
|
|
259
298
|
Handling media queries via properties.
|
|
260
299
|
|
|
261
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
262
|
-
| :------------------- | :---------------------------------- | :---------------- |
|
|
263
|
-
| **Small Breakpoint** | `@media (width >= 40rem) { (etc) }` | `sm:grid-cols-3` | `{ sm: { gridCols: 3 } }`
|
|
264
|
-
| **Medium Layout** | `@media (width >= 48rem) { (etc) }` | `md:flex` | `{ md: {
|
|
265
|
-
| **Large Spacing** | `@media (width >= 64rem) { (etc) }` | `lg:px-8` | `{ lg: { px: 8 } }`
|
|
300
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) |
|
|
301
|
+
| :------------------- | :---------------------------------- | :---------------- | :---------------------------- |
|
|
302
|
+
| **Small Breakpoint** | `@media (width >= 40rem) { (etc) }` | `sm:grid-cols-3` | `{ sm: { gridCols: 3 } }` |
|
|
303
|
+
| **Medium Layout** | `@media (width >= 48rem) { (etc) }` | `md:flex` | `{ md: { display: 'flex' } }` |
|
|
304
|
+
| **Large Spacing** | `@media (width >= 64rem) { (etc) }` | `lg:px-8` | `{ lg: { px: 8 } }` |
|
|
266
305
|
|
|
267
306
|
## Dark Mode
|
|
268
307
|
|
|
@@ -341,9 +380,9 @@ Standard interactive states.
|
|
|
341
380
|
| **Hover, Focus, Active** | `hover:bg-red focus:bg-blue active:bg-green` | `{ hover: { bg: 'red' }, focus: { bg: 'blue' }, active: { bg: 'green' } }` | |
|
|
342
381
|
| **First/Last Child** | `first:pt-0 last:pb-0` | `{ first: { pt: 0 }, last: { pb: 0 } }` | |
|
|
343
382
|
| **Odd/Even Child** | `odd:bg-white even:bg-gray` | `{ odd: { bg: 'white' }, even: { bg: 'gray' } }` | |
|
|
344
|
-
| **First of Type** | `first-of-type:block` | `{ firstOfType: {
|
|
345
|
-
| **Only Child** | `only:block` | `{ only: {
|
|
346
|
-
| **Empty** | `empty:hidden` | `{ empty: {
|
|
383
|
+
| **First of Type** | `first-of-type:block` | `{ firstOfType: { display: 'block' } }` | **Sugar**: CamelCase alias. |
|
|
384
|
+
| **Only Child** | `only:block` | `{ only: { display: 'block' } }` | |
|
|
385
|
+
| **Empty** | `empty:hidden` | `{ empty: { display: 'none' } }` | |
|
|
347
386
|
| **Visited** | `visited:text-purple` | `{ visited: { color: 'purple' } }` | |
|
|
348
387
|
| **Focus Within** | `focus-within:ring` | `{ focusWithin: { ring: true } }` | **Sugar**: CamelCase alias. |
|
|
349
388
|
| **Focus Visible** | `focus-visible:ring` | `{ focusVisible: { ring: true } }` | **Sugar**: CamelCase alias. |
|
|
@@ -353,11 +392,11 @@ Standard interactive states.
|
|
|
353
392
|
|
|
354
393
|
Styling based on descendants.
|
|
355
394
|
|
|
356
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
357
|
-
| :----------------- | :-------------------------- |
|
|
358
|
-
| **Has Descendant** | `has-[img]:bg-blue` | `{ has: { img: { bg: 'blue' } } }`
|
|
359
|
-
| **Has State** | `has-[:checked]:bg-blue` | `{ has: { checked: { bg: 'blue' } } }`
|
|
360
|
-
| **Arbitrary Has** | `has-[.custom-class]:block` | `{ has: { '.custom-class': {
|
|
395
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
396
|
+
| :----------------- | :-------------------------- | :--------------------------------------------------- | :------------------------------------ |
|
|
397
|
+
| **Has Descendant** | `has-[img]:bg-blue` | `{ has: { img: { bg: 'blue' } } }` | **Sugar**: Nested selector. |
|
|
398
|
+
| **Has State** | `has-[:checked]:bg-blue` | `{ has: { checked: { bg: 'blue' } } }` | **Sugar**: Auto-detects pseudo-class. |
|
|
399
|
+
| **Arbitrary Has** | `has-[.custom-class]:block` | `{ has: { '.custom-class': { display: 'block' } } }` | |
|
|
361
400
|
|
|
362
401
|
## Styling based on parent state (Groups)
|
|
363
402
|
|
|
@@ -369,76 +408,76 @@ Styling children based on parent `group` class.
|
|
|
369
408
|
| **Group Focus** | `group-focus:text-white` | `{ group: { focus: { color: 'white' } } }` | |
|
|
370
409
|
| **Group Active** | `group-active:text-white` | `{ group: { active: { color: 'white' } } }` | |
|
|
371
410
|
| **Nested Groups** | `group-hover/name:text-white` | `{ group: { name: { hover: { color: 'white' } } } }` | **Sugar**: Scope name as nested key. |
|
|
372
|
-
| **Arbitrary Groups** | `group-[.is-published]:block` | `{ group: { '.is-published': {
|
|
373
|
-
| **Group Has** | `group-has-[a]:block` | `{ group: { has: { a: {
|
|
411
|
+
| **Arbitrary Groups** | `group-[.is-published]:block` | `{ group: { '.is-published': { display: 'block' } } }` | |
|
|
412
|
+
| **Group Has** | `group-has-[a]:block` | `{ group: { has: { a: { display: 'block' } } } }` | |
|
|
374
413
|
| **Group Data** | `group-data-[active]:text-blue` | `{ group: { data: { active: { color: 'blue' } } } }` | **Sugar**: Nested `data` key. |
|
|
375
414
|
| **Group Data (named)** | `group-data-[active]/card:text-blue` | `{ group: { card: { data: { active: { color: 'blue' } } } } }` | Name before `data` key. |
|
|
376
|
-
| **Group Data (value match)** | `group-data-[state=open]:block` | `{ group: { data: { 'state=open': {
|
|
377
|
-
| **Group ARIA** | `group-aria-expanded:block` | `{ group: { aria: { expanded: {
|
|
378
|
-
| **Group ARIA (arbitrary)** | `group-aria-[current=page]:font-bold` | `{ group: { aria: { 'current=page': {
|
|
415
|
+
| **Group Data (value match)** | `group-data-[state=open]:block` | `{ group: { data: { 'state=open': { display: 'block' } } } }` | `=` in key → bracket form always. |
|
|
416
|
+
| **Group ARIA** | `group-aria-expanded:block` | `{ group: { aria: { expanded: { display: 'block' } } } }` | Standard states: bare form. |
|
|
417
|
+
| **Group ARIA (arbitrary)** | `group-aria-[current=page]:font-bold` | `{ group: { aria: { 'current=page': { weight: 'bold' } } } }` | Non-standard: bracket form. |
|
|
379
418
|
|
|
380
419
|
## Styling based on sibling state (Peers)
|
|
381
420
|
|
|
382
421
|
Styling based on previous sibling `peer` class.
|
|
383
422
|
|
|
384
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
385
|
-
| :-------------------------- | :---------------------------------- |
|
|
386
|
-
| **Peer Hover** | `peer-hover:text-white` | `{ peer: { hover: { color: 'white' } } }`
|
|
387
|
-
| **Peer Checked** | `peer-checked:bg-blue` | `{ peer: { checked: { bg: 'blue' } } }`
|
|
388
|
-
| **Differentiating Peers** | `peer-checked/name:bg-blue` | `{ peer: { name: { checked: { bg: 'blue' } } } }`
|
|
389
|
-
| **Arbitrary Peers** | `peer-[.is-dirty]:block` | `{ peer: { '.is-dirty': {
|
|
390
|
-
| **Peer Data** | `peer-data-[active]:text-blue` | `{ peer: { data: { active: { color: 'blue' } } } }`
|
|
391
|
-
| **Peer Data (value match)** | `peer-data-[state=open]:block` | `{ peer: { data: { 'state=open': {
|
|
392
|
-
| **Peer ARIA** | `peer-aria-checked:bg-blue` | `{ peer: { aria: { checked: { bg: 'blue' } } } }`
|
|
393
|
-
| **Peer ARIA (arbitrary)** | `peer-aria-[invalid=true]:text-red` | `{ peer: { aria: { 'invalid=true': { color: 'red' } } } }`
|
|
423
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
424
|
+
| :-------------------------- | :---------------------------------- | :----------------------------------------------------------- | :----------------------------------- |
|
|
425
|
+
| **Peer Hover** | `peer-hover:text-white` | `{ peer: { hover: { color: 'white' } } }` | **Sugar**: Nested scope. |
|
|
426
|
+
| **Peer Checked** | `peer-checked:bg-blue` | `{ peer: { checked: { bg: 'blue' } } }` | |
|
|
427
|
+
| **Differentiating Peers** | `peer-checked/name:bg-blue` | `{ peer: { name: { checked: { bg: 'blue' } } } }` | **Sugar**: Scope name as nested key. |
|
|
428
|
+
| **Arbitrary Peers** | `peer-[.is-dirty]:block` | `{ peer: { '.is-dirty': { display: 'block' } } }` | |
|
|
429
|
+
| **Peer Data** | `peer-data-[active]:text-blue` | `{ peer: { data: { active: { color: 'blue' } } } }` | **Sugar**: Nested `data` key. |
|
|
430
|
+
| **Peer Data (value match)** | `peer-data-[state=open]:block` | `{ peer: { data: { 'state=open': { display: 'block' } } } }` | `=` in key → bracket form always. |
|
|
431
|
+
| **Peer ARIA** | `peer-aria-checked:bg-blue` | `{ peer: { aria: { checked: { bg: 'blue' } } } }` | Standard states: bare form. |
|
|
432
|
+
| **Peer ARIA (arbitrary)** | `peer-aria-[invalid=true]:text-red` | `{ peer: { aria: { 'invalid=true': { color: 'red' } } } }` | Non-standard: bracket form. |
|
|
394
433
|
|
|
395
434
|
## :not()
|
|
396
435
|
|
|
397
436
|
Inverse conditions.
|
|
398
437
|
|
|
399
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
400
|
-
| :--------------- | :---------------------------------- |
|
|
401
|
-
| **Not Hover** | `not-hover:opacity-75` | `{ not: { hover: { opacity: 75 } } }`
|
|
402
|
-
| **Not First** | `not-first:mt-4` | `{ not: { first: { mt: 4 } } }`
|
|
403
|
-
| **Not Supports** | `not-supports-[display:grid]:block` | `{ not: { supports: { 'display:grid': {
|
|
438
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
439
|
+
| :--------------- | :---------------------------------- | :---------------------------------------------------------------- | :--- |
|
|
440
|
+
| **Not Hover** | `not-hover:opacity-75` | `{ not: { hover: { opacity: 75 } } }` | |
|
|
441
|
+
| **Not First** | `not-first:mt-4` | `{ not: { first: { mt: 4 } } }` | |
|
|
442
|
+
| **Not Supports** | `not-supports-[display:grid]:block` | `{ not: { supports: { 'display:grid': { display: 'block' } } } }` | |
|
|
404
443
|
|
|
405
444
|
## Pseudo-elements
|
|
406
445
|
|
|
407
446
|
Advanced content styling.
|
|
408
447
|
|
|
409
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
410
|
-
| :--------------- | :---------------------- |
|
|
411
|
-
| **Before/After** | `before:content-['']` | `{ before: { (etc) } }`
|
|
412
|
-
| **Placeholder** | `placeholder:text-gray` | `{ placeholder: { color: 'gray' } }`
|
|
413
|
-
| **File** | `file:border` | `{ file: { border: true } }`
|
|
414
|
-
| **Marker** | `marker:text-blue` | `{ marker: { color: 'blue' } }`
|
|
415
|
-
| **Selection** | `selection:bg-pink` | `{ selection: { bg: 'pink' } }`
|
|
416
|
-
| **First Line** | `first-line:uppercase` | `{ firstLine: {
|
|
417
|
-
| **First Letter** | `first-letter:text-7xl` | `{ firstLetter: { text: '7xl' } }`
|
|
418
|
-
| **Backdrop** | `backdrop:blur` | `{ backdrop: { blur: true } }`
|
|
448
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
449
|
+
| :--------------- | :---------------------- | :---------------------------------------------- | :-------------------- |
|
|
450
|
+
| **Before/After** | `before:content-['']` | `{ before: { (etc) } }` | Defaults used. |
|
|
451
|
+
| **Placeholder** | `placeholder:text-gray` | `{ placeholder: { color: 'gray' } }` | |
|
|
452
|
+
| **File** | `file:border` | `{ file: { border: true } }` | |
|
|
453
|
+
| **Marker** | `marker:text-blue` | `{ marker: { color: 'blue' } }` | |
|
|
454
|
+
| **Selection** | `selection:bg-pink` | `{ selection: { bg: 'pink' } }` | |
|
|
455
|
+
| **First Line** | `first-line:uppercase` | `{ firstLine: { textTransform: 'uppercase' } }` | **Sugar**: CamelCase. |
|
|
456
|
+
| **First Letter** | `first-letter:text-7xl` | `{ firstLetter: { text: '7xl' } }` | **Sugar**: CamelCase. |
|
|
457
|
+
| **Backdrop** | `backdrop:blur` | `{ backdrop: { blur: true } }` | |
|
|
419
458
|
|
|
420
459
|
## Media & Feature Queries
|
|
421
460
|
|
|
422
461
|
Environment-based styling.
|
|
423
462
|
|
|
424
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
425
|
-
| :-------------------- | :-------------------------------- |
|
|
426
|
-
| **Breakpoints** | `md:block lg:flex` | `{ md: {
|
|
427
|
-
| **Container Queries** | `@md:block @lg:flex` | `{ '@md': {
|
|
428
|
-
| **Reduced Motion** | `motion-reduce:hidden` | `{ motionReduce: {
|
|
429
|
-
| **Prefers Contrast** | `contrast-more:border` | `{ contrastMore: { border: true } }`
|
|
430
|
-
| **Forced Colors** | `forced-colors:border-gray` | `{ forcedColors: { borderColor: 'gray' } }`
|
|
431
|
-
| **Inverted Colors** | `inverted-colors:invert` | `{ invertedColors: { invert: true } }`
|
|
432
|
-
| **Pointer** | `pointer-coarse:p-4` | `{ pointerCoarse: { p: 4 } }`
|
|
433
|
-
| **Any-Pointer** | `any-pointer-fine:cursor-pointer` | `{ anyPointerFine: { cursor: 'pointer' } }`
|
|
434
|
-
| **User Valid** | `user-valid:border-green-500` | `{ userValid: { borderColor: 'green-500' } }`
|
|
435
|
-
| **User Invalid** | `user-invalid:border-red-500` | `{ userInvalid: { borderColor: 'red-500' } }`
|
|
436
|
-
| **Details Content** | `details-content:block` | `{ detailsContent: {
|
|
437
|
-
| **Print** | `print:hidden` | `{ print: {
|
|
438
|
-
| **Orientation** | `portrait:hidden` | `{ portrait: {
|
|
439
|
-
| **Scripting** | `noscript:block` | `{ noscript: {
|
|
440
|
-
| **Supports** | `supports-[display:grid]:grid` | `{ supports: { 'display:grid': {
|
|
441
|
-
| **Starting Style** | `starting:opacity-0` | `{ starting: { opacity: 0 } }`
|
|
463
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
464
|
+
| :-------------------- | :-------------------------------- | :------------------------------------------------------------ | :---------------------------- |
|
|
465
|
+
| **Breakpoints** | `md:block lg:flex` | `{ md: { display: 'block' }, lg: { display: 'flex' } }` | |
|
|
466
|
+
| **Container Queries** | `@md:block @lg:flex` | `{ '@md': { display: 'block' }, '@lg': { display: 'flex' } }` | **Note**: String key for `@`. |
|
|
467
|
+
| **Reduced Motion** | `motion-reduce:hidden` | `{ motionReduce: { display: 'none' } }` | **Sugar**: CamelCase. |
|
|
468
|
+
| **Prefers Contrast** | `contrast-more:border` | `{ contrastMore: { border: true } }` | |
|
|
469
|
+
| **Forced Colors** | `forced-colors:border-gray` | `{ forcedColors: { borderColor: 'gray' } }` | **Sugar**: CamelCase. |
|
|
470
|
+
| **Inverted Colors** | `inverted-colors:invert` | `{ invertedColors: { invert: true } }` | **Sugar**: CamelCase. |
|
|
471
|
+
| **Pointer** | `pointer-coarse:p-4` | `{ pointerCoarse: { p: 4 } }` | **Sugar**: CamelCase. |
|
|
472
|
+
| **Any-Pointer** | `any-pointer-fine:cursor-pointer` | `{ anyPointerFine: { cursor: 'pointer' } }` | v4.1. **Sugar**: CamelCase. |
|
|
473
|
+
| **User Valid** | `user-valid:border-green-500` | `{ userValid: { borderColor: 'green-500' } }` | v4.1. Form validation state. |
|
|
474
|
+
| **User Invalid** | `user-invalid:border-red-500` | `{ userInvalid: { borderColor: 'red-500' } }` | v4.1. Form validation state. |
|
|
475
|
+
| **Details Content** | `details-content:block` | `{ detailsContent: { display: 'block' } }` | v4.1. **Sugar**: CamelCase. |
|
|
476
|
+
| **Print** | `print:hidden` | `{ print: { display: 'none' } }` | |
|
|
477
|
+
| **Orientation** | `portrait:hidden` | `{ portrait: { display: 'none' } }` | |
|
|
478
|
+
| **Scripting** | `noscript:block` | `{ noscript: { display: 'block' } }` | |
|
|
479
|
+
| **Supports** | `supports-[display:grid]:grid` | `{ supports: { 'display:grid': { display: 'grid' } } }` | |
|
|
480
|
+
| **Starting Style** | `starting:opacity-0` | `{ starting: { opacity: 0 } }` | |
|
|
442
481
|
|
|
443
482
|
## Attribute Selectors
|
|
444
483
|
|
|
@@ -476,8 +515,8 @@ Targeting specific screen sizes and container states.
|
|
|
476
515
|
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
477
516
|
| :----------------------- | :-------------------------- | :------------------------ | :------------------------------------------------ | :---------------------------------- |
|
|
478
517
|
| **Mobile First** | `min-width: (etc)` | `w-full md:w-1/2` | `{ w: 'full', md: { w: '1/2' } }` | Unprefixed utilities target mobile. |
|
|
479
|
-
| **Breakpoint Range** | `768px <= width < 1280px` | `md:max-xl:flex` | `{ md: { maxXl: {
|
|
480
|
-
| **Single Breakpoint** | `md only` | `md:max-lg:flex` | `{ md: { maxLg: {
|
|
518
|
+
| **Breakpoint Range** | `768px <= width < 1280px` | `md:max-xl:flex` | `{ md: { maxXl: { display: 'flex' } } }` | **Sugar**: CamelCase for `max-xl`. |
|
|
519
|
+
| **Single Breakpoint** | `md only` | `md:max-lg:flex` | `{ md: { maxLg: { display: 'flex' } } }` | Target specific range. |
|
|
481
520
|
| **Custom Breakpoint** | `@media (min-width: 320px)` | `min-[320px]:text-center` | `{ min: { '[320px]': { textAlign: 'center' } } }` | Arbitrary one-off breakpoint. |
|
|
482
521
|
| **Max-Width Breakpoint** | `@media (max-width: 600px)` | `max-[600px]:bg-sky-300` | `{ max: { '[600px]': { bg: 'sky-300' } } }` | |
|
|
483
522
|
|
|
@@ -497,15 +536,15 @@ The `container` class sets `width: 100%` and applies responsive max-widths.
|
|
|
497
536
|
|
|
498
537
|
The `@container` class enables CSS container queries.
|
|
499
538
|
|
|
500
|
-
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
501
|
-
| :----------------------- | :------------------- |
|
|
502
|
-
| **Mark Container** | `@container` | `{ '@container': true }`
|
|
503
|
-
| **Named Container** | `@container/sidebar` | `{ '@container': 'sidebar' }`
|
|
504
|
-
| **Container Breakpoint** | `@md:flex` | `{ '@md': {
|
|
505
|
-
| **Named Query** | `@md/sidebar:block` | `{ '@md': { sidebar: {
|
|
506
|
-
| **Container Range** | `@sm:@max-md:block` | `{ '@sm': { '@maxMd': {
|
|
507
|
-
| **Arbitrary Query** | `@min-[475px]:flex` | `{ '@min': { '[475px]': {
|
|
508
|
-
| **Container Units** | `w-[50cqw]` | `{ w: '50cqw' }`
|
|
539
|
+
| Concept | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
540
|
+
| :----------------------- | :------------------- | :----------------------------------------------- | :---------------------------------------- |
|
|
541
|
+
| **Mark Container** | `@container` | `{ '@container': true }` | |
|
|
542
|
+
| **Named Container** | `@container/sidebar` | `{ '@container': 'sidebar' }` | **Sugar**: Value string = container name. |
|
|
543
|
+
| **Container Breakpoint** | `@md:flex` | `{ '@md': { display: 'flex' } }` | **Note**: `@` prefix in key. |
|
|
544
|
+
| **Named Query** | `@md/sidebar:block` | `{ '@md': { sidebar: { display: 'block' } } }` | **Sugar**: Nest name inside query key. |
|
|
545
|
+
| **Container Range** | `@sm:@max-md:block` | `{ '@sm': { '@maxMd': { display: 'block' } } }` | |
|
|
546
|
+
| **Arbitrary Query** | `@min-[475px]:flex` | `{ '@min': { '[475px]': { display: 'flex' } } }` | |
|
|
547
|
+
| **Container Units** | `w-[50cqw]` | `{ w: '50cqw' }` | |
|
|
509
548
|
|
|
510
549
|
## Dark mode
|
|
511
550
|
|
|
@@ -836,14 +875,14 @@ Controlling the width of an element's borders.
|
|
|
836
875
|
|
|
837
876
|
Controlling the color of an element's borders.
|
|
838
877
|
|
|
839
|
-
| Concept | CSS Rule
|
|
840
|
-
| :-------------------- |
|
|
841
|
-
| **Color** | `border-color:
|
|
842
|
-
| **Opacity** | `border-color:
|
|
843
|
-
| **CSS Var + Opacity** | `border-color: var(--c) / 50`
|
|
844
|
-
| **X/Y/T/R/B/L** | `border-color:
|
|
845
|
-
| **Arbitrary** | `border-color:
|
|
846
|
-
| **Variable** | `border-color: var(--c)`
|
|
878
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
879
|
+
| :-------------------- | :------------------------------------------------------------------------- | :------------------ | :---------------------------------------------- | :----------------------------------------- |
|
|
880
|
+
| **Color** | `border-color: var(--color-red-500)` | `border-red-500` | `{ borderColor: 'red-500' }` | |
|
|
881
|
+
| **Opacity** | `border-color: color-mix(in oklab, var(--color-red-500) 50%, transparent)` | `border-red-500/50` | `{ borderColor: { color: 'red-500', op: 50 } }` | |
|
|
882
|
+
| **CSS Var + Opacity** | `border-color: var(--c) / 50` | `border-(--c)/50` | `{ borderColor: { color: '--c', op: 50 } }` | CSS variables are auto-wrapped in `(...)`. |
|
|
883
|
+
| **X/Y/T/R/B/L** | `border-top-color: var(--color-red-500)` | `border-t-red-500` | `{ borderTColor: 'red-500' }` | Verbose keys to avoid conflict with Width. |
|
|
884
|
+
| **Arbitrary** | `border-color: #50d71e` | `border-[#50d71e]` | `{ borderColor: '#50d71e' }` | |
|
|
885
|
+
| **Variable** | `border-color: var(--c)` | `border-(--c)` | `{ borderColor: '--c' }` | |
|
|
847
886
|
|
|
848
887
|
## Border Style
|
|
849
888
|
|
|
@@ -877,13 +916,13 @@ Utilities for controlling the border width between elements.
|
|
|
877
916
|
|
|
878
917
|
Utilities for controlling the border color between elements.
|
|
879
918
|
|
|
880
|
-
| Concept | CSS Rule
|
|
881
|
-
| :-------------------- |
|
|
882
|
-
| **Color** | `border-color:
|
|
883
|
-
| **Opacity** | `border-color:
|
|
884
|
-
| **CSS Var + Opacity** | `border-color: var(--c) / 50`
|
|
885
|
-
| **Arbitrary** | `border-color:
|
|
886
|
-
| **Variable** | `border-color: var(--c)`
|
|
919
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
920
|
+
| :-------------------- | :------------------------------------------------------------------------- | :------------------ | :---------------------------------------------- | :----------------------------------------- |
|
|
921
|
+
| **Color** | `border-color: var(--color-red-500)` | `divide-red-500` | `{ divideColor: 'red-500' }` | Applied between children. |
|
|
922
|
+
| **Opacity** | `border-color: color-mix(in oklab, var(--color-red-500) 50%, transparent)` | `divide-red-500/50` | `{ divideColor: { color: 'red-500', op: 50 } }` | |
|
|
923
|
+
| **CSS Var + Opacity** | `border-color: var(--c) / 50` | `divide-(--c)/50` | `{ divideColor: { color: '--c', op: 50 } }` | CSS variables are auto-wrapped in `(...)`. |
|
|
924
|
+
| **Arbitrary** | `border-color: #50d71e` | `divide-[#50d71e]` | `{ divideColor: '#50d71e' }` | |
|
|
925
|
+
| **Variable** | `border-color: var(--c)` | `divide-(--c)` | `{ divideColor: '--c' }` | |
|
|
887
926
|
|
|
888
927
|
## Divide Style
|
|
889
928
|
|
|
@@ -911,11 +950,11 @@ Controlling the width of an element's outline.
|
|
|
911
950
|
|
|
912
951
|
Controlling the color of an element's outline.
|
|
913
952
|
|
|
914
|
-
| Concept | CSS Rule
|
|
915
|
-
| :------------ |
|
|
916
|
-
| **Color** | `outline-color:
|
|
917
|
-
| **Arbitrary** | `outline-color:
|
|
918
|
-
| **Variable** | `outline-color: var(--c)`
|
|
953
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
954
|
+
| :------------ | :------------------------------------ | :------------------ | :---------------------------- | :--- |
|
|
955
|
+
| **Color** | `outline-color: var(--color-red-500)` | `outline-red-500` | `{ outlineColor: 'red-500' }` | |
|
|
956
|
+
| **Arbitrary** | `outline-color: #50d71e` | `outline-[#50d71e]` | `{ outlineColor: '#50d71e' }` | |
|
|
957
|
+
| **Variable** | `outline-color: var(--c)` | `outline-(--c)` | `{ outlineColor: '--c' }` | |
|
|
919
958
|
|
|
920
959
|
## Outline Style
|
|
921
960
|
|
|
@@ -2150,31 +2189,31 @@ Controlling box model sizing.
|
|
|
2150
2189
|
|
|
2151
2190
|
Controlling display box type.
|
|
2152
2191
|
|
|
2153
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop
|
|
2154
|
-
| :--------------------- | :---------------------------- | :------------------- | :---------------------------------- |
|
|
2155
|
-
| **Block** | `display: block` | `block` | `{ display: 'block' }` |
|
|
2156
|
-
| **Inline Block** | `display: inline-block` | `inline-block` | `{ display: 'inline-block' }` |
|
|
2157
|
-
| **Inline** | `display: inline` | `inline` | `{ display: 'inline' }` |
|
|
2158
|
-
| **Flex** | `display: flex` | `flex` | `{ display: 'flex' }` |
|
|
2159
|
-
| **Inline Flex** | `display: inline-flex` | `inline-flex` | `{ display: 'inline-flex' }` |
|
|
2160
|
-
| **Grid** | `display: grid` | `grid` | `{ display: 'grid' }` |
|
|
2161
|
-
| **Inline Grid** | `display: inline-grid` | `inline-grid` | `{ display: 'inline-grid' }` |
|
|
2162
|
-
| **Contents** | `display: contents` | `contents` | `{ display: 'contents' }` |
|
|
2163
|
-
| **Table** | `display: table` | `table` | `{ display: 'table' }` |
|
|
2164
|
-
| **Inline Table** | `display: inline-table` | `inline-table` | `{ display: 'inline-table' }` |
|
|
2165
|
-
| **Table Caption** | `display: table-caption` | `table-caption` | `{ display: 'table-caption' }` |
|
|
2166
|
-
| **Table Cell** | `display: table-cell` | `table-cell` | `{ display: 'table-cell' }` |
|
|
2167
|
-
| **Table Column** | `display: table-column` | `table-column` | `{ display: 'table-column' }` |
|
|
2168
|
-
| **Table Column Group** | `display: table-column-group` | `table-column-group` | `{ display: 'table-column-group' }` |
|
|
2169
|
-
| **Table Footer Group** | `display: table-footer-group` | `table-footer-group` | `{ display: 'table-footer-group' }` |
|
|
2170
|
-
| **Table Header Group** | `display: table-header-group` | `table-header-group` | `{ display: 'table-header-group' }` |
|
|
2171
|
-
| **Table Row Group** | `display: table-row-group` | `table-row-group` | `{ display: 'table-row-group' }` |
|
|
2172
|
-
| **Table Row** | `display: table-row` | `table-row` | `{ display: 'table-row' }` |
|
|
2173
|
-
| **Flow Root** | `display: flow-root` | `flow-root` | `{ display: 'flow-root' }` |
|
|
2174
|
-
| **List Item** | `display: list-item` | `list-item` | `{ display: 'list-item' }` |
|
|
2175
|
-
| **Hidden** | `display: none` | `hidden` | `{ display: 'none' }` |
|
|
2176
|
-
| **Screen Reader Only** | `position: absolute; ...` | `sr-only` |
|
|
2177
|
-
| **Not Screen Reader** | `position: static; ...` | `not-sr-only` |
|
|
2192
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop |
|
|
2193
|
+
| :--------------------- | :---------------------------- | :------------------- | :---------------------------------- |
|
|
2194
|
+
| **Block** | `display: block` | `block` | `{ display: 'block' }` |
|
|
2195
|
+
| **Inline Block** | `display: inline-block` | `inline-block` | `{ display: 'inline-block' }` |
|
|
2196
|
+
| **Inline** | `display: inline` | `inline` | `{ display: 'inline' }` |
|
|
2197
|
+
| **Flex** | `display: flex` | `flex` | `{ display: 'flex' }` |
|
|
2198
|
+
| **Inline Flex** | `display: inline-flex` | `inline-flex` | `{ display: 'inline-flex' }` |
|
|
2199
|
+
| **Grid** | `display: grid` | `grid` | `{ display: 'grid' }` |
|
|
2200
|
+
| **Inline Grid** | `display: inline-grid` | `inline-grid` | `{ display: 'inline-grid' }` |
|
|
2201
|
+
| **Contents** | `display: contents` | `contents` | `{ display: 'contents' }` |
|
|
2202
|
+
| **Table** | `display: table` | `table` | `{ display: 'table' }` |
|
|
2203
|
+
| **Inline Table** | `display: inline-table` | `inline-table` | `{ display: 'inline-table' }` |
|
|
2204
|
+
| **Table Caption** | `display: table-caption` | `table-caption` | `{ display: 'table-caption' }` |
|
|
2205
|
+
| **Table Cell** | `display: table-cell` | `table-cell` | `{ display: 'table-cell' }` |
|
|
2206
|
+
| **Table Column** | `display: table-column` | `table-column` | `{ display: 'table-column' }` |
|
|
2207
|
+
| **Table Column Group** | `display: table-column-group` | `table-column-group` | `{ display: 'table-column-group' }` |
|
|
2208
|
+
| **Table Footer Group** | `display: table-footer-group` | `table-footer-group` | `{ display: 'table-footer-group' }` |
|
|
2209
|
+
| **Table Header Group** | `display: table-header-group` | `table-header-group` | `{ display: 'table-header-group' }` |
|
|
2210
|
+
| **Table Row Group** | `display: table-row-group` | `table-row-group` | `{ display: 'table-row-group' }` |
|
|
2211
|
+
| **Table Row** | `display: table-row` | `table-row` | `{ display: 'table-row' }` |
|
|
2212
|
+
| **Flow Root** | `display: flow-root` | `flow-root` | `{ display: 'flow-root' }` |
|
|
2213
|
+
| **List Item** | `display: list-item` | `list-item` | `{ display: 'list-item' }` |
|
|
2214
|
+
| **Hidden** | `display: none` | `hidden` | `{ display: 'none' }` |
|
|
2215
|
+
| **Screen Reader Only** | `position: absolute; ...` | `sr-only` | `{ srOnly: true }` |
|
|
2216
|
+
| **Not Screen Reader** | `position: static; ...` | `not-sr-only` | `{ notSrOnly: true }` |
|
|
2178
2217
|
|
|
2179
2218
|
## Floats
|
|
2180
2219
|
|
|
@@ -2205,10 +2244,10 @@ Controlling flow relative to floats.
|
|
|
2205
2244
|
|
|
2206
2245
|
Controlling stacking contexts.
|
|
2207
2246
|
|
|
2208
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note
|
|
2209
|
-
| :---------- | :------------------- | :---------------- | :------------------------- |
|
|
2210
|
-
| **Isolate** | `isolation: isolate` | `isolate` | `{ isolation: 'isolate' }` |
|
|
2211
|
-
| **Auto** | `isolation: auto` | `isolation-auto` | `{ isolation: 'auto' }` |
|
|
2247
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
2248
|
+
| :---------- | :------------------- | :---------------- | :------------------------- | :--- |
|
|
2249
|
+
| **Isolate** | `isolation: isolate` | `isolate` | `{ isolation: 'isolate' }` | |
|
|
2250
|
+
| **Auto** | `isolation: auto` | `isolation-auto` | `{ isolation: 'auto' }` | |
|
|
2212
2251
|
|
|
2213
2252
|
## Object Fit
|
|
2214
2253
|
|
|
@@ -2282,13 +2321,13 @@ Controlling scroll chaining.
|
|
|
2282
2321
|
|
|
2283
2322
|
Controlling positioning.
|
|
2284
2323
|
|
|
2285
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop
|
|
2286
|
-
| :----------- | :------------------- | :---------------- | :------------------------- |
|
|
2287
|
-
| **Static** | `position: static` | `static` | `{ position: 'static' }` |
|
|
2288
|
-
| **Fixed** | `position: fixed` | `fixed` | `{ position: 'fixed' }` |
|
|
2289
|
-
| **Absolute** | `position: absolute` | `absolute` | `{ position: 'absolute' }` |
|
|
2290
|
-
| **Relative** | `position: relative` | `relative` | `{ position: 'relative' }` |
|
|
2291
|
-
| **Sticky** | `position: sticky` | `sticky` | `{ position: 'sticky' }` |
|
|
2324
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop |
|
|
2325
|
+
| :----------- | :------------------- | :---------------- | :------------------------- |
|
|
2326
|
+
| **Static** | `position: static` | `static` | `{ position: 'static' }` |
|
|
2327
|
+
| **Fixed** | `position: fixed` | `fixed` | `{ position: 'fixed' }` |
|
|
2328
|
+
| **Absolute** | `position: absolute` | `absolute` | `{ position: 'absolute' }` |
|
|
2329
|
+
| **Relative** | `position: relative` | `relative` | `{ position: 'relative' }` |
|
|
2330
|
+
| **Sticky** | `position: sticky` | `sticky` | `{ position: 'sticky' }` |
|
|
2292
2331
|
|
|
2293
2332
|
## Top / Right / Bottom / Left (Placement)
|
|
2294
2333
|
|
|
@@ -2343,11 +2382,11 @@ Positioning mapped elements.
|
|
|
2343
2382
|
|
|
2344
2383
|
Controlling visibility without layout change.
|
|
2345
2384
|
|
|
2346
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop
|
|
2347
|
-
| :------------ | :--------------------- | :---------------- | :--------------------------- |
|
|
2348
|
-
| **Visible** | `visibility: visible` | `visible` | `{ visibility: 'visible' }` |
|
|
2349
|
-
| **Invisible** | `visibility: hidden` | `invisible` | `{ visibility: 'hidden' }` |
|
|
2350
|
-
| **Collapse** | `visibility: collapse` | `collapse` | `{ visibility: 'collapse' }` |
|
|
2385
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop |
|
|
2386
|
+
| :------------ | :--------------------- | :---------------- | :--------------------------- |
|
|
2387
|
+
| **Visible** | `visibility: visible` | `visible` | `{ visibility: 'visible' }` |
|
|
2388
|
+
| **Invisible** | `visibility: hidden` | `invisible` | `{ visibility: 'hidden' }` |
|
|
2389
|
+
| **Collapse** | `visibility: collapse` | `collapse` | `{ visibility: 'collapse' }` |
|
|
2351
2390
|
|
|
2352
2391
|
## Z-Index
|
|
2353
2392
|
|
|
@@ -3099,7 +3138,7 @@ Controlling the font size.
|
|
|
3099
3138
|
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
3100
3139
|
| :--------------- | :------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------- | :---------------------------------------------------------------- |
|
|
3101
3140
|
| **Scale** | `font-size: (size); line-height: (leading)` | `text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`, `text-4xl`, `text-5xl`, `text-6xl`, `text-7xl`, `text-8xl`, `text-9xl` | `{ text: 'xs' }`, `{ text: 'sm' }` etc. | Sets size & leading. |
|
|
3102
|
-
| **Number** | `font-size: 16px` | `text-[16px]` | `{ text: '16px' }` |
|
|
3141
|
+
| **Number** | `font-size: 16px` | `text-[16px]` | `{ text: '16px' }` | `text` is the single canonical key. |
|
|
3103
3142
|
| **Arbitrary** | `font-size: 1.5rem` | `text-[1.5rem]` | `{ text: '1.5rem' }` | |
|
|
3104
3143
|
| **CSS Variable** | `font-size: var(--size)` | `text-(length:--size)` | `{ text: '--size' }` | **Sugar**: Auto-detects `--`. Type hint disambiguates from color. |
|
|
3105
3144
|
|
|
@@ -3109,11 +3148,11 @@ Controlling the font weight.
|
|
|
3109
3148
|
|
|
3110
3149
|
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
3111
3150
|
| :--------------- | :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------ | :----------------------------------------------------------------- |
|
|
3112
|
-
| **Keywords** | `font-weight: 100-900` | `font-thin`, `font-extralight`, `font-light`, `font-normal`, `font-medium`, `font-semibold`, `font-bold`, `font-extrabold`, `font-black` | `{
|
|
3113
|
-
| **Number** | `font-weight: 100-900` | `font-100`, `font-200`, `font-300`, `font-400`, `font-500`, `font-600`, `font-700`, `font-800`, `font-900` | `{
|
|
3114
|
-
| **Alias** | (Sugar) | `font-bold` | `{ weight: 'bold' }` | Sugar for `
|
|
3115
|
-
| **Arbitrary** | `font-weight: 550` | `font-[550]` | `{
|
|
3116
|
-
| **CSS Variable** | `font-weight: var(--w)` | `font-(weight:--w)` | `{
|
|
3151
|
+
| **Keywords** | `font-weight: 100-900` | `font-thin`, `font-extralight`, `font-light`, `font-normal`, `font-medium`, `font-semibold`, `font-bold`, `font-extrabold`, `font-black` | `{ weight: 'thin' }`, `{ weight: 'extralight' }` etc. | |
|
|
3152
|
+
| **Number** | `font-weight: 100-900` | `font-100`, `font-200`, `font-300`, `font-400`, `font-500`, `font-600`, `font-700`, `font-800`, `font-900` | `{ weight: 100 }`, `{ weight: 200 }` etc. | v4 shorthand. |
|
|
3153
|
+
| **Alias** | (Sugar) | `font-bold` | `{ weight: 'bold' }` | Sugar for `weight`. |
|
|
3154
|
+
| **Arbitrary** | `font-weight: 550` | `font-[550]` | `{ weight: 550 }` | |
|
|
3155
|
+
| **CSS Variable** | `font-weight: var(--w)` | `font-(weight:--w)` | `{ weight: '--w' }` | **Sugar**: Auto-detects `--`. Type hint disambiguates from family. |
|
|
3117
3156
|
|
|
3118
3157
|
## Font Stretch
|
|
3119
3158
|
|
|
@@ -3152,12 +3191,12 @@ Controlling font-feature-settings. Added in Tailwind v4.2.
|
|
|
3152
3191
|
|
|
3153
3192
|
Controlling the font style and smoothing.
|
|
3154
3193
|
|
|
3155
|
-
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax)
|
|
3156
|
-
| :-------------- | :------------------------------------ | :--------------------- |
|
|
3157
|
-
| **Italic** | `font-style: italic` | `italic` | `{
|
|
3158
|
-
| **Not Italic** | `font-style: normal` | `not-italic` | `{
|
|
3159
|
-
| **Antialiased** | `-webkit-font-smoothing: antialiased` | `antialiased` | `{
|
|
3160
|
-
| **Subpixel** | `-webkit-font-smoothing: auto` | `subpixel-antialiased` | `{
|
|
3194
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
3195
|
+
| :-------------- | :------------------------------------ | :--------------------- | :------------------------------- | :--------------------------- |
|
|
3196
|
+
| **Italic** | `font-style: italic` | `italic` | `{ fontStyle: 'italic' }` | |
|
|
3197
|
+
| **Not Italic** | `font-style: normal` | `not-italic` | `{ fontStyle: 'normal' }` | Resets to upright. |
|
|
3198
|
+
| **Antialiased** | `-webkit-font-smoothing: antialiased` | `antialiased` | `{ fontSmoothing: 'grayscale' }` | Grayscale antialiasing. |
|
|
3199
|
+
| **Subpixel** | `-webkit-font-smoothing: auto` | `subpixel-antialiased` | `{ fontSmoothing: 'subpixel' }` | Subpixel (RGB) antialiasing. |
|
|
3161
3200
|
|
|
3162
3201
|
## Letter Spacing (Tracking)
|
|
3163
3202
|
|
|
@@ -3222,28 +3261,23 @@ Controlling the text color.
|
|
|
3222
3261
|
|
|
3223
3262
|
Controlling the decoration of text.
|
|
3224
3263
|
|
|
3225
|
-
| Concept
|
|
3226
|
-
|
|
|
3227
|
-
| **Line (string)**
|
|
3228
|
-
| **Style**
|
|
3229
|
-
| **Thickness**
|
|
3230
|
-
| **Offset**
|
|
3231
|
-
| **Color**
|
|
3232
|
-
| **Arbitrary**
|
|
3233
|
-
| **Var**
|
|
3234
|
-
| **Bool underline** | `text-decoration-line: underline` | `underline` | `{ underline: true }` | **Sugar**. `false` = NOOP. |
|
|
3235
|
-
| **Bool overline** | `text-decoration-line: overline` | `overline` | `{ overline: true }` | **Sugar**. `false` = NOOP. |
|
|
3236
|
-
| **Bool through** | `text-decoration-line: line-through` | `line-through` | `{ lineThrough: true }` | **Sugar**. `false` = NOOP. |
|
|
3237
|
-
| **Bool reset** | `text-decoration-line: none` | `no-underline` | `{ noUnderline: true }` | **Sugar**. Resets ALL decoration. Use for responsive reset. |
|
|
3264
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
3265
|
+
| :---------------- | :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------- | :------------------------------------------------------------ |
|
|
3266
|
+
| **Line (string)** | `text-decoration-line: underline` | `underline`, `overline`, `line-through`, `no-underline` | `{ decoration: 'underline' }` etc. | String key. `'none'` → `no-underline` (resets ALL decoration) |
|
|
3267
|
+
| **Style** | `text-decoration-style: solid` | `decoration-solid`, `decoration-dashed`, `decoration-dotted`, `decoration-double`, `decoration-wavy` | `{ decorationStyle: 'solid' }` etc. | |
|
|
3268
|
+
| **Thickness** | `text-decoration-thickness: auto` | `decoration-0`, `decoration-1`, `decoration-2`, `decoration-4`, `decoration-8`, `decoration-auto`, `decoration-from-font` | `{ decorationThickness: 1 }` etc. | |
|
|
3269
|
+
| **Offset** | `text-underline-offset: auto` | `underline-offset-0`, `underline-offset-1`, `underline-offset-2`, `underline-offset-4`, `underline-offset-8`, `underline-offset-auto` | `{ underlineOffset: 1 }` etc. | |
|
|
3270
|
+
| **Color** | `text-decoration-color: var(--color-blue-500)` | `decoration-blue-500` | `{ decorationColor: 'blue-500' }` | |
|
|
3271
|
+
| **Arbitrary** | `text-decoration: (value)` | `decoration-[3px]` | `{ decorationThickness: '3px' }` | |
|
|
3272
|
+
| **Var** | `text-decoration: (value)` | `decoration-(--v)` | `{ decorationThickness: '--v' }` | **Sugar**: Auto-detects `--`. |
|
|
3238
3273
|
|
|
3239
3274
|
## Text Transform
|
|
3240
3275
|
|
|
3241
3276
|
Controlling the capitalization of text.
|
|
3242
3277
|
|
|
3243
|
-
| Concept
|
|
3244
|
-
|
|
|
3245
|
-
| **Transform**
|
|
3246
|
-
| **Boolean (Sugar)** | `text-transform: uppercase` | `uppercase` | `{ uppercase: true }` | **Sugar**. Overwrites `textTransform`. |
|
|
3278
|
+
| Concept | CSS Rule | Tailwind v4 Class | `sz` Prop (Object Syntax) | Note |
|
|
3279
|
+
| :------------ | :-------------------------- | :---------------------------------------------------- | :------------------------------------------------------------------------------ | :--------------------- |
|
|
3280
|
+
| **Transform** | `text-transform: uppercase` | `uppercase`, `lowercase`, `capitalize`, `normal-case` | `{ textTransform: 'uppercase' }` (also `'lowercase'`, `'capitalize'`, `'none'`) | `'none'` → normal-case |
|
|
3247
3281
|
|
|
3248
3282
|
## Text Overflow & Whitespace
|
|
3249
3283
|
|
|
@@ -3313,7 +3347,7 @@ Static items are pre-computed at build time; conditional items use `_szMerge` at
|
|
|
3313
3347
|
```tsx
|
|
3314
3348
|
<div
|
|
3315
3349
|
sz={[
|
|
3316
|
-
{
|
|
3350
|
+
{ display: "flex", items: "center", p: 4 }, // always — extracted at build time
|
|
3317
3351
|
isActive && { bg: "blue-500" }, // runtime conditional
|
|
3318
3352
|
isDisabled && { opacity: 50, cursor: "not-allowed" },
|
|
3319
3353
|
]}
|
|
@@ -3355,10 +3389,10 @@ import { szv } from "csszyx";
|
|
|
3355
3389
|
|
|
3356
3390
|
const buttonSz = szv({
|
|
3357
3391
|
base: {
|
|
3358
|
-
|
|
3392
|
+
display: "inline-flex",
|
|
3359
3393
|
items: "center",
|
|
3360
3394
|
rounded: "md",
|
|
3361
|
-
|
|
3395
|
+
weight: "medium",
|
|
3362
3396
|
},
|
|
3363
3397
|
variants: {
|
|
3364
3398
|
variant: {
|
|
@@ -3443,20 +3477,21 @@ SSR-safe: on the server, returns class names without CSSOM access.
|
|
|
3443
3477
|
For dynamic classes at runtime (the only runtime overhead):
|
|
3444
3478
|
|
|
3445
3479
|
```tsx
|
|
3446
|
-
import { _sz,
|
|
3480
|
+
import { _sz, _szMerge } from '@csszyx/runtime';
|
|
3447
3481
|
|
|
3448
3482
|
// Concatenate class strings
|
|
3449
3483
|
<div className={_sz('base-class', conditionalClass)} />
|
|
3450
3484
|
|
|
3451
|
-
// Conditional class
|
|
3452
|
-
<div className={
|
|
3485
|
+
// Conditional class — plain JS conditionals compose with _sz
|
|
3486
|
+
<div className={_sz('base-class', isActive && 'active-class')} />
|
|
3487
|
+
<div className={isActive ? 'active-class' : 'inactive-class'} />
|
|
3453
3488
|
|
|
3454
|
-
// Switch/enum
|
|
3455
|
-
<div className={
|
|
3489
|
+
// Switch/enum — a plain object lookup
|
|
3490
|
+
<div className={{
|
|
3456
3491
|
loading: 'opacity-50',
|
|
3457
3492
|
error: 'border-red-500',
|
|
3458
3493
|
success: 'border-green-500',
|
|
3459
|
-
}
|
|
3494
|
+
}[status]} />
|
|
3460
3495
|
|
|
3461
3496
|
// Merge (last wins for conflicts)
|
|
3462
3497
|
<div className={_szMerge(baseClasses, overrideClasses)} />
|
|
@@ -3471,6 +3506,51 @@ import { __szColorVar } from "csszyx/lite";
|
|
|
3471
3506
|
// __szColorVar('#ff0000') → '#ff0000'
|
|
3472
3507
|
```
|
|
3473
3508
|
|
|
3509
|
+
## Nested Element Routing — splitBox + class toolkit
|
|
3510
|
+
|
|
3511
|
+
When a caller passes one flat `className` to a component that renders nested elements, `splitBox` partitions it at the CSS box-model border line so each element gets the classes that act on it. Pure string functions, framework-agnostic. The class-token → box-role map is generated from the compiler's property tables (never drifts).
|
|
3512
|
+
|
|
3513
|
+
```tsx
|
|
3514
|
+
import { splitBox, classify, has, pick, omit, stripSzProps } from '@csszyx/runtime';
|
|
3515
|
+
|
|
3516
|
+
// Partition: outer = border-outward (margin/position/border/sizing/bg/shadow/transform/visibility),
|
|
3517
|
+
// inner = border-inward (padding/overflow/display/layout/gap/text/paint-inside/interactivity)
|
|
3518
|
+
const { outer, inner } = splitBox('m-4 px-2 md:flex');
|
|
3519
|
+
// outer: "m-4" inner: "px-2 md:flex"
|
|
3520
|
+
|
|
3521
|
+
// Override any default per call (BoxSelector = box-role | category | class-prefix | { category: value })
|
|
3522
|
+
splitBox('overflow-hidden p-4', { outer: ['overflow'] });
|
|
3523
|
+
// outer: "overflow-hidden" inner: "p-4"
|
|
3524
|
+
|
|
3525
|
+
// Toolkit: csszyx owns the truth (box-role/category), your project owns the rule
|
|
3526
|
+
classify('inset-ring-2'); // { role: 'inner', category: 'ring' }
|
|
3527
|
+
has('p-2 overflow-y-auto', 'overflow'); // true
|
|
3528
|
+
pick('m-4 text-sm', 'text'); // "text-sm"
|
|
3529
|
+
omit('p-2 overflow-y-auto flex', 'overflow'); // "p-2 flex"
|
|
3530
|
+
|
|
3531
|
+
// A scroller scrolls only when the outer frame clips (project-owned dependency rule)
|
|
3532
|
+
const dep = has(outer, { overflow: 'hidden' }) ? 'overflow-y-auto h-full' : '';
|
|
3533
|
+
|
|
3534
|
+
// stripSzProps: drop sz before forwarding ...rest to the DOM (guards uncompiled files
|
|
3535
|
+
// whose raw sz would leak as sz="[object Object]"; dev-warns once on a raw-object sz)
|
|
3536
|
+
function Box({ sz, ...rest }) { return <div {...stripSzProps(rest)} />; }
|
|
3537
|
+
```
|
|
3538
|
+
|
|
3539
|
+
## Security — untrusted sz
|
|
3540
|
+
|
|
3541
|
+
csszyx is safe-by-default for AUTHORED sz (compiled to class strings at build time). When sz comes from UNTRUSTED input (JSON-driven UI, CMS, user data), it controls keys and values that reach the runtime CSS pipeline — purify it.
|
|
3542
|
+
|
|
3543
|
+
```tsx
|
|
3544
|
+
import { dynamic, purifySz } from '@csszyx/dynamic';
|
|
3545
|
+
// stripSzProps is exported from '@csszyx/runtime'
|
|
3546
|
+
|
|
3547
|
+
// Untrusted sz → dynamic() runtime CSS: purify first (allowlist + value sanitize + proto guard)
|
|
3548
|
+
const className = dynamic(purifySz(untrustedSzFromJson));
|
|
3549
|
+
// strict (default) also strips url()/image-set()/@import/expression(); { strict:false } for trusted input
|
|
3550
|
+
```
|
|
3551
|
+
|
|
3552
|
+
Guarantees on the runtime path: CSS is injected via atomic `insertRule` (a `}`/`</style>` rule-breakout throws, no 2nd rule/markup); declaration value + arbitrary property name are validated before injection; recursion depth is capped (`SzDepthError`). `dynamic()`/`_sz`/`_szMerge` return React-escaped-only strings — safe in `className={}`, NEVER interpolate into raw HTML. `stripSzProps(props)` keeps a raw `sz` object off the DOM. SSR mangle map is schema-validated (`isValidMangleMap`); `verifyMangleChecksumAsync` gives real integrity verification without the WASM core (tamper-detection, not authentication). The constructable-`adoptedStyleSheets` injection path is CSP-clean (no inline style text). Posture: treat all sz/DOM/config as untrusted by default.
|
|
3553
|
+
|
|
3474
3554
|
## SSR Hydration
|
|
3475
3555
|
|
|
3476
3556
|
CSSzyx validates that server and client use the same mangle map:
|
|
@@ -3524,6 +3604,11 @@ In production, class names are mangled for maximum compression:
|
|
|
3524
3604
|
|
|
3525
3605
|
Output: `<div class="z y x" />` — the CSS `.z { padding: 1rem }` etc. is injected automatically.
|
|
3526
3606
|
|
|
3607
|
+
Set `production: { mangle: false }` to keep readable class names — the supported way to
|
|
3608
|
+
inspect the emitted CSS, and recommended for hybrid apps that also ship non-csszyx
|
|
3609
|
+
stylesheets keyed on the original class names. To check what a single `sz` object
|
|
3610
|
+
compiles to without a build, run `csszyx explain "{ p: 4, bg: 'blue-500' }"`.
|
|
3611
|
+
|
|
3527
3612
|
### AST budget guard
|
|
3528
3613
|
|
|
3529
3614
|
Files larger than 50 000 AST nodes throw `ASTBudgetExceededError` at
|
|
@@ -3541,6 +3626,19 @@ Or exclude the file from csszyx processing entirely before parsing:
|
|
|
3541
3626
|
...csszyx({ exclude: ['src/generated/**', /icon-dump\.tsx$/] })
|
|
3542
3627
|
```
|
|
3543
3628
|
|
|
3629
|
+
## Monorepo Workspace Packages (compilePackages)
|
|
3630
|
+
|
|
3631
|
+
`/packages/` is hard-ignored by default (a published library ships pre-extracted
|
|
3632
|
+
CSS). To compile `sz` in a monorepo workspace package you author, opt it in by
|
|
3633
|
+
directory name — only `/packages/` is relaxed, `node_modules`/`.next` stay ignored:
|
|
3634
|
+
|
|
3635
|
+
```js
|
|
3636
|
+
...csszyx({ compilePackages: ['vui'] }) // compiles sz in /packages/vui/**
|
|
3637
|
+
```
|
|
3638
|
+
|
|
3639
|
+
A `/packages/` file with `sz` that is not opted in is skipped silently (no CSS);
|
|
3640
|
+
csszyx warns at build end and lists those files.
|
|
3641
|
+
|
|
3544
3642
|
## Theme Auto-Scan (Custom Tokens → TypeScript Types)
|
|
3545
3643
|
|
|
3546
3644
|
When using Tailwind v4 `@theme` blocks for custom design tokens, enable `build.scanCss`
|
|
@@ -3631,12 +3729,13 @@ of classes the developer has explicitly flagged as "not yet decided."
|
|
|
3631
3729
|
| `inline-flex` | `{ display: 'inline-flex' }` |
|
|
3632
3730
|
| `hidden` | `{ display: 'none' }` |
|
|
3633
3731
|
|
|
3634
|
-
|
|
3732
|
+
Boolean sugar like `{ flex: true }` was removed — use `{ display: 'flex' }`.
|
|
3635
3733
|
The migrate command uses `display` so duplicate display utilities are visible as
|
|
3636
3734
|
one semantic CSS property. Conflicting display utilities in the same variant
|
|
3637
3735
|
scope, such as `block flex` or `md:block md:flex`, are left unresolved instead
|
|
3638
3736
|
of guessed. `flex flex-1` is safe and migrates to
|
|
3639
|
-
`{ display: 'flex', flex: '1' }
|
|
3737
|
+
`{ display: 'flex', flex: '1' }` (the `flex` shorthand stays — only the
|
|
3738
|
+
`flex: true` display alias was removed).
|
|
3640
3739
|
|
|
3641
3740
|
### `--resolve-todos` — apply the resolution map
|
|
3642
3741
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csszyx/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for csszyx — enables AI agents to understand and generate sz props",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
32
32
|
"zod": "^3.23.8",
|
|
33
|
-
"@csszyx/cli": "0.
|
|
34
|
-
"@csszyx/unplugin": "0.
|
|
35
|
-
"@csszyx/compiler": "0.
|
|
33
|
+
"@csszyx/cli": "0.10.0",
|
|
34
|
+
"@csszyx/unplugin": "0.10.0",
|
|
35
|
+
"@csszyx/compiler": "0.10.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"typescript": "^6.0.3",
|