The JavaScript configuration and plugin snippets here target Tailwind CSS 3. Tailwind CSS 4 uses CSS-first configuration; explicitly load a compatible legacy config with @config rather than assuming automatic discovery. Upgrade guide.
Tailwind plug-in mechanism (addUtilities/addComponents) belongs to 👉 The watershed of "from being able to use Tailwind → to being able to build a component library/standard system"
1. What is the plug-in mechanism for?
In one sentence:
Use JS to batch generate Tailwind classes instead of handwriting CSS
You can:
- Define a set of utilities
- Define a set of components
- Read design variables in
theme() - Automatic support for
hover / dark / responsive
2. Basic structure of plug-in
// tailwind.config.js
import plugin from 'tailwindcss/plugin'
export default {
theme: { extend: {} },
plugins: [
plugin(function ({ addUtilities, addComponents, theme }) {
// 写插件逻辑
})
]
}3. addUtilities (tool class)
When to use it?
👉 Single function, freely combinable atomic capabilities
Such as:
.safe-top.text-shadow.scrollbar-hide
1️⃣ The simplest example
addUtilities({
'.safe-top': {
paddingTop: 'env(safe-area-inset-top)'
}
})<div class="safe-top"></div>2️⃣ Support responsive / hover / dark
addUtilities(
{
'.text-shadow': {
textShadow: '0 2px 4px rgba(0,0,0,.2)'
}
},
['responsive', 'hover', 'dark']
)<div class="hover:text-shadow dark:text-shadow"></div>3️⃣ Get value from theme (core)
addUtilities(
{
'.bg-primary-gradient': {
background: `linear-gradient(
90deg,
${theme('colors.primary.500')},
${theme('colors.primary.700')}
)`
}
}
)📌 This step = plug-in + design system integration
4️⃣ Batch generation of utilities (common techniques)
const sizes = {
sm: '4px',
md: '8px',
lg: '16px'
}
addUtilities(
Object.entries(sizes).map(([key, value]) => ({
[`.blur-${key}`]: { filter: `blur(${value})` }
}))
)Use:
<div class="blur-md"></div>4. addComponents (component class)
When to use it?
👉 A complete set of fixed structure styles
Such as:
- Button
- Card
- Alert
- Tag
1️⃣ Button component example (core)
addComponents({
'.btn': {
padding: '8px 16px',
borderRadius: theme('borderRadius.md'),
fontWeight: '500'
},
'.btn-primary': {
backgroundColor: theme('colors.primary.500'),
color: '#fff',
'&:hover': {
backgroundColor: theme('colors.primary.700')
}
}
})<button class="btn btn-primary"></button>📌 btn = structure 📌 btn-primary = skin
2️⃣ Responsive components
addComponents({
'.card': {
padding: '16px',
'@screen md': {
padding: '24px'
}
}
})3️⃣ Dark Mode component
addComponents({
'.card': {
backgroundColor: '#fff',
'.dark &': {
backgroundColor: '#111'
}
}
})5. addUtilities vs addComponents (key comparison)
| dimensions | addUtilities | addComponents |
|---|---|---|
| Positioning | Atomic capabilities | Component packaging |
| Combinatoriality | Strong | Weak |
| Is there semantics | Almost none | Strong |
| Suitable for scenarios | Functional classes | Component library |
📌 Rule of Thumb
Detachable → utilities Don’t want to dismantle → components
6. addBase (by the way)
Used to change the default label style
addBase({
'h1': { fontSize: theme('fontSize.xl') },
'h2': { fontSize: theme('fontSize.lg') }
})📌 Commonly used in:
- reset
- markdown style
7. Practical combat: Make an "enterprise-level button plug-in"
// plugins/button.js
import plugin from 'tailwindcss/plugin'
export default plugin(({ addComponents, theme }) => {
addComponents({
'.btn': {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: theme('borderRadius.md'),
padding: '8px 16px',
fontWeight: '500'
},
'.btn-primary': {
backgroundColor: theme('colors.primary.500'),
color: '#fff',
'&:hover': {
backgroundColor: theme('colors.primary.700')
}
},
'.btn-danger': {
backgroundColor: theme('colors.danger.500'),
color: '#fff'
}
})
})// tailwind.config.js
import button from './plugins/button'
plugins: [button]8. Best practices for combining with Vue components
The Tailwind plug-in is responsible for "style rules"
Vue components are responsible for "structure + logic"
<button class="btn" :class="`btn-${type}`">
<slot />
</button>9. Common pitfalls (you will definitely encounter them)
1️⃣ Will classes generated by plug-ins also be purged?
✅ No (plug-ins are injected during build)
2️⃣ How to choose plug-in vs @apply?
- Public system → plug-in
- local component → @apply