Skip to content

Commit dc3ef8c

Browse files
committed
feat(skill): tailwind-impl-apply-directive
1 parent 12e7abe commit dc3ef8c

4 files changed

Lines changed: 1436 additions & 0 deletions

File tree

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
---
2+
name: tailwind-impl-apply-directive
3+
description: >
4+
Use when writing custom CSS that needs to share design tokens with
5+
Tailwind utilities via @apply, organizing component / base / utility
6+
CSS via @layer, or fixing the "Cannot apply unknown utility class"
7+
error in Vue, Svelte, or CSS-module scoped styles by adding
8+
@reference. Prevents the utility-extraction anti-pattern (wrapping
9+
every utility in @apply destroys utility-first benefits like JIT
10+
pruning, in-context readability, and consistent design tokens), the
11+
scoped-style trap in v4 (Vue SFC, Svelte SFC, and CSS modules
12+
evaluate @apply against an empty token registry without @reference,
13+
failing with "Cannot apply unknown utility class"), the layer-order
14+
trap (custom CSS outside @layer leaks above utilities and gets
15+
overridden), the important-modifier syntax flip between v3
16+
(leading bang, !font-bold) and v4 (trailing bang, font-bold!), and
17+
the @apply !important keyword vs modifier confusion. Covers @apply
18+
semantics (copies utility declarations into the current rule),
19+
@layer base / components / utilities (specificity ascends in that
20+
order, matches @tailwind ordering in v3 and @import "tailwindcss"
21+
cascade in v4), @reference "path" (v4 only, makes tokens visible
22+
in scoped contexts without duplicating CSS), the v3 vs v4 important
23+
syntax flip, plugin-vs-layer ordering, and when @apply is the right
24+
tool versus when component extraction (React / Vue / Svelte
25+
component) is the right tool instead.
26+
Keywords: tailwind @apply, @apply utility, apply directive,
27+
custom CSS tailwind, share tokens custom CSS, @layer base
28+
components utilities, layer order tailwind, tailwind 3
29+
@apply !important, tailwind 4 @apply font-bold!, important
30+
modifier tailwind, !font-bold v3, font-bold! v4, leading
31+
bang vs trailing bang, @reference tailwindcss, @reference
32+
app.css, Cannot apply unknown utility class, Cannot apply
33+
unknown utility, vue scoped style apply, svelte scoped
34+
style apply, css modules apply, scoped @apply broken v4,
35+
tailwind component extraction, when not to use @apply,
36+
@apply anti pattern, button class @apply, when to extract
37+
utilities, plugin order @layer, third-party library
38+
override tailwind, override third party styles, @apply
39+
inside scoped style, tailwind 3-4 directive differences.
40+
license: MIT
41+
compatibility: "Designed for Claude Code. Requires Tailwind CSS v3.4 or v4.0+."
42+
metadata:
43+
author: OpenAEC-Foundation
44+
version: "1.0"
45+
---
46+
47+
# @apply, @layer, @reference
48+
49+
`@apply` lets custom CSS reuse Tailwind utility declarations. `@layer`
50+
sorts custom CSS into Tailwind's cascade. `@reference` (v4) makes
51+
tokens visible inside scoped style blocks.
52+
53+
ALWAYS prefer component extraction (React, Vue, Svelte component)
54+
over @apply when the consumer is a component framework. NEVER reach
55+
for @apply just because a class name appears twice. See
56+
`references/anti-patterns.md` AP-1 for the full philosophy.
57+
58+
Companion skills :
59+
60+
- `tailwind-impl-config-v3` : v3 JS-config and PostCSS pipeline
61+
- `tailwind-impl-config-v4` : v4 CSS-first config and directives
62+
- `tailwind-impl-build-vite` : Vite plugin wiring
63+
64+
## Quick Reference
65+
66+
### @apply (both versions)
67+
68+
```css
69+
.btn-primary {
70+
@apply rounded-lg bg-blue-500 px-4 py-2 text-white;
71+
}
72+
```
73+
74+
ALWAYS use inside a regular CSS selector, NEVER at the top level. The
75+
declarations are copied verbatim from the utility class into the rule.
76+
77+
### @layer (both versions)
78+
79+
```css
80+
@layer base {
81+
h1 { @apply text-4xl font-bold; }
82+
}
83+
84+
@layer components {
85+
.btn { @apply rounded bg-blue-500 px-4 py-2 text-white; }
86+
}
87+
88+
@layer utilities {
89+
.text-shadow-sm { text-shadow: 0 1px 2px rgb(0 0 0 / 0.1); }
90+
}
91+
```
92+
93+
Order in the cascade : `base < components < utilities`. Anything in
94+
`utilities` wins over `components` ; anything in `components` wins
95+
over `base`.
96+
97+
### @reference (v4 only)
98+
99+
```vue
100+
<style scoped>
101+
@reference "../app.css";
102+
103+
.card { @apply rounded bg-white shadow; }
104+
</style>
105+
```
106+
107+
The first line MUST be `@reference` when the scoped block uses
108+
`@apply` or `@variant`. Without it, v4 raises `Cannot apply unknown
109+
utility class`.
110+
111+
### Important modifier syntax flip
112+
113+
| Version | In HTML class | Inside @apply |
114+
| ------- | ---------------- | ----------------------------------- |
115+
| v3 | `!font-bold` | `@apply font-bold !important;` |
116+
| v4 | `font-bold!` | `@apply font-bold!;` |
117+
118+
NEVER write `!font-bold` in v4. NEVER write `font-bold!` in v3.
119+
120+
## Decision Trees
121+
122+
### Should I use @apply or extract a component ?
123+
124+
```
125+
Are you in a component framework (React, Vue, Svelte, Solid) ?
126+
├── Yes : ALWAYS extract a component. Pass props for variants.
127+
│ @apply is the wrong tool inside a framework that already
128+
│ gives you component reuse with type-checked props.
129+
└── No : continue
130+
Is the consumer plain HTML, MDX, or a CMS template ?
131+
├── Yes : @apply is acceptable for shared class names (.btn, .card).
132+
│ Document the class semantics next to the @apply rule.
133+
└── No : continue
134+
Is this a third-party-library override
135+
(react-select dropdown, Algolia DocSearch, embedded widget) ?
136+
├── Yes : @apply is the right tool. The library owns the markup ;
137+
│ you can only style it from outside.
138+
└── No : revisit. Most uses of @apply outside the above two cases
139+
are utility hiding, not utility reuse.
140+
```
141+
142+
### Which @layer should this rule go in ?
143+
144+
```
145+
What kind of CSS am I adding ?
146+
├── Global element default (h1, p, body) : @layer base
147+
├── Named, multi-utility component class (.btn) : @layer components
148+
├── Single-purpose helper class (.text-shadow) : @layer utilities
149+
└── None : Tailwind will sort it AFTER utilities. Almost always wrong.
150+
```
151+
152+
### My @apply errors with "Cannot apply unknown utility class". Why ?
153+
154+
```
155+
v3 or v4 ?
156+
├── v3 : the utility is not generated.
157+
│ - JIT did not see the class in any scanned file
158+
│ - The class is typo'd or uses a custom token that is not
159+
│ registered in tailwind.config.js theme
160+
│ Fix : add the file to content, fix the typo, or extend the theme.
161+
└── v4 : you are inside a scoped style block (Vue, Svelte, CSS module).
162+
Tokens are not visible there by default.
163+
Fix : add `@reference "../app.css";` as the FIRST line of the
164+
scoped block. The path points to your global entry CSS.
165+
```
166+
167+
## Patterns
168+
169+
### Pattern : extracting a component class
170+
171+
```css
172+
@layer components {
173+
.btn {
174+
@apply inline-flex items-center rounded px-4 py-2 font-medium;
175+
}
176+
.btn-primary {
177+
@apply btn bg-blue-500 text-white hover:bg-blue-600;
178+
}
179+
}
180+
```
181+
182+
ALWAYS put @apply rules inside `@layer components`. Without the layer,
183+
the rule lands after Tailwind utilities, so `class="btn px-2"` cannot
184+
override the layer's `px-4` without `!`.
185+
186+
### Pattern : overriding third-party widget CSS
187+
188+
```css
189+
@layer components {
190+
.select2-dropdown {
191+
@apply rounded-b-lg shadow-md;
192+
}
193+
.ais-SearchBox-input {
194+
@apply rounded border border-gray-300 px-3 py-2;
195+
}
196+
}
197+
```
198+
199+
When the library renders markup you do not control, @apply is the
200+
clean bridge between your design tokens and their selectors.
201+
202+
### Pattern : base layer for element defaults
203+
204+
```css
205+
@layer base {
206+
body {
207+
@apply bg-gray-50 text-gray-900 antialiased;
208+
}
209+
h1 { @apply text-4xl font-bold tracking-tight; }
210+
h2 { @apply text-3xl font-semibold; }
211+
}
212+
```
213+
214+
Base layer rules apply to every matching element without needing a
215+
class. ALWAYS use base for "every h1 should look like this" not
216+
"this specific h1 should look like this".
217+
218+
### Pattern : v4 scoped @apply in Vue / Svelte
219+
220+
Vue SFC :
221+
222+
```vue
223+
<script setup lang="ts">
224+
import "./style.css"
225+
</script>
226+
227+
<template>
228+
<button class="btn">Save</button>
229+
</template>
230+
231+
<style scoped>
232+
@reference "./style.css";
233+
234+
.btn {
235+
@apply rounded bg-blue-500 px-4 py-2 text-white;
236+
}
237+
</style>
238+
```
239+
240+
Svelte component :
241+
242+
```svelte
243+
<style>
244+
@reference "../app.css";
245+
246+
h1 { @apply text-3xl font-bold; }
247+
</style>
248+
```
249+
250+
The `@reference` line is REQUIRED in v4 for scoped @apply. It loads
251+
the token registry into the file's parse context WITHOUT emitting
252+
the global CSS again.
253+
254+
### Pattern : !important modifier
255+
256+
v3 in HTML :
257+
258+
```html
259+
<button class="!font-bold">Force bold</button>
260+
```
261+
262+
v3 inside @apply :
263+
264+
```css
265+
.btn { @apply font-bold !important; }
266+
```
267+
268+
v4 in HTML :
269+
270+
```html
271+
<button class="font-bold!">Force bold</button>
272+
```
273+
274+
v4 inside @apply :
275+
276+
```css
277+
.btn { @apply font-bold!; }
278+
```
279+
280+
NEVER mix the syntaxes. The v3 leading-bang form does NOT parse in v4.
281+
282+
## Anti-Patterns (summary)
283+
284+
NEVER wrap every reused utility set in @apply. Component extraction
285+
(React/Vue/Svelte component with props) is the right tool inside a
286+
component framework.
287+
288+
NEVER put @apply rules outside `@layer`. They land after Tailwind's
289+
utility layer and lose all override behavior.
290+
291+
NEVER omit `@reference` in v4 Vue / Svelte / CSS-modules scoped styles
292+
that use @apply. The error is always "Cannot apply unknown utility class".
293+
294+
NEVER mix `!font-bold` (v3) and `font-bold!` (v4) syntax across versions.
295+
296+
NEVER use @apply for a single utility. `class="font-bold"` in the
297+
template is already that.
298+
299+
See `references/anti-patterns.md` for the full catalog.
300+
301+
## Plugin Order and @layer Interaction
302+
303+
Tailwind sorts the final CSS as :
304+
305+
1. `@layer base` (your custom base + Tailwind preflight)
306+
2. `@layer components` (your component classes + plugin component classes)
307+
3. `@layer utilities` (your utility classes + Tailwind utilities + plugin utilities)
308+
309+
A custom utility class declared via `@layer utilities` competes with
310+
Tailwind utilities at the same specificity. ALWAYS rely on order
311+
within the layer (later wins) rather than `!important`.
312+
313+
Plugins that register utilities or components inject INTO these layers.
314+
A `addUtilities({ ... })` call lands in `utilities`, NOT before yours.
315+
ALWAYS verify final order in DevTools when a plugin override misbehaves.
316+
317+
## v3 vs v4 Differences
318+
319+
| Feature | v3 | v4 |
320+
| ------------------------ | ---------------------------------------- | ---------------------------------------- |
321+
| @apply syntax | `@apply font-bold;` | `@apply font-bold;` |
322+
| Important inside @apply | `@apply font-bold !important;` | `@apply font-bold!;` |
323+
| Important in HTML | `class="!font-bold"` | `class="font-bold!"` |
324+
| @layer support | `@layer base/components/utilities` | `@layer base/components/utilities` |
325+
| @reference | NOT supported (not needed) | REQUIRED in scoped style blocks |
326+
| Scoped @apply works ? | Yes, via PostCSS context | Only with `@reference` |
327+
328+
## Reference Links
329+
330+
- `references/methods.md` : every directive's exact syntax, accepted
331+
forms, order rules, layer semantics
332+
- `references/examples.md` : full patterns for components, layered
333+
base styles, scoped @apply in Vue/Svelte/CSS modules
334+
- `references/anti-patterns.md` : utility-hiding mistakes, scoped-style
335+
errors, layer mistakes, important syntax errors
336+
337+
## Sources
338+
339+
- v4 directives reference : https://tailwindcss.com/docs/functions-and-directives
340+
- v3 directives reference : https://v3.tailwindcss.com/docs/functions-and-directives
341+
- v4 scoped @apply trap : https://github.com/tailwindlabs/tailwindcss/issues/16346
342+
- L-002 (project lesson) : v4 scoped style + @apply ALWAYS needs @reference

0 commit comments

Comments
 (0)