
Unocss
- 14.4k installs
- 5.7k repo stars
- Updated June 23, 2026
- antfu/skills
UnoCSS is a skill covering the atomic CSS engine with presets, transformers, and configuration patterns.
About
UnoCSS is an atomic CSS engine that generates utility classes on-demand. Developers use it as a faster, more flexible alternative to Tailwind CSS for styling web applications. Useful for teams prioritizing build performance and customization.
- Atomic CSS engine with presets and transformers
- Part of Anthony Fu's curated opinionated best practices
- Integrates with Vite and modern JavaScript tooling
Unocss by the numbers
- 14,385 all-time installs (skills.sh)
- +159 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #40 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
unocss capabilities & compatibility
- Use cases
- frontend · ui design · web design
- IDEs
- vscode · cursor ide · jetbrains · webstorm · neovim · zed
- Pricing
- Free
npx skills add https://github.com/antfu/skills --skill unocssAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14.4k |
|---|---|
| repo stars | ★ 5.7k |
| Security audit | 2 / 3 scanners passed |
| Last updated | June 23, 2026 |
| Repository | antfu/skills ↗ |
How do you configure UnoCSS presets and shortcuts?
UnoCSS is an atomic CSS engine that generates utility classes on-demand. Developers use it as a faster, more flexible alternative to Tailwind CSS for styling web applications. Useful for teams priori
Who is it for?
Frontend engineers building apps with Vite, Nuxt, or other modern JavaScript tooling
Skip if: Projects standardized on Tailwind CSS config alone without migrating to UnoCSS.
When should I use this skill?
A developer asks to set up uno.config.ts, add UnoCSS presets, shortcuts, or transformer directives in a frontend project.
What you get
uno.config.ts with presets, shortcuts, transformers, and project-ready utility-first CSS setup
- uno.config.ts configuration file
- Preset and shortcut definitions
- Transformer-enabled utility CSS pipeline
By the numbers
- Generated from UnoCSS source on 2026-01-28
- Documents six presets and two transformers in the recommended config
Files
UnoCSS is an instant atomic CSS engine designed to be flexible and extensible. The core is un-opinionated - all CSS utilities are provided via presets. It's a superset of Tailwind CSS, so you can reuse your Tailwind knowledge for basic syntax usage.
Important: Before writing UnoCSS code, agents should check for uno.config.* or unocss.config.* files in the project root to understand what presets, rules, and shortcuts are available. If the project setup is unclear, avoid using attributify mode and other advanced features - stick to basic class usage.
The skill is based on UnoCSS 66.x, generated at 2026-01-28.
Core
| Topic | Description | Reference |
|---|---|---|
| Configuration | Config file setup and all configuration options | core-config |
| Rules | Static and dynamic rules for generating CSS utilities | core-rules |
| Shortcuts | Combine multiple rules into single shorthands | core-shortcuts |
| Theme | Theming system for colors, breakpoints, and design tokens | core-theme |
| Variants | Apply variations like hover:, dark:, responsive to rules | core-variants |
| Extracting | How UnoCSS extracts utilities from source code | core-extracting |
| Safelist & Blocklist | Force include or exclude specific utilities | core-safelist |
| Layers & Preflights | CSS layer ordering and raw CSS injection | core-layers |
Presets
Main Presets
| Topic | Description | Reference |
|---|---|---|
| Preset Wind3 | Tailwind CSS v3 / Windi CSS compatible preset (most common) | preset-wind3 |
| Preset Wind4 | Tailwind CSS v4 compatible preset with modern CSS features | preset-wind4 |
| Preset Mini | Minimal preset with essential utilities for custom builds | preset-mini |
Feature Presets
| Topic | Description | Reference |
|---|---|---|
| Preset Icons | Pure CSS icons using Iconify with any icon set | preset-icons |
| Preset Attributify | Group utilities in HTML attributes instead of class | preset-attributify |
| Preset Typography | Prose classes for typographic defaults | preset-typography |
| Preset Web Fonts | Easy Google Fonts and other web fonts integration | preset-web-fonts |
| Preset Tagify | Use utilities as HTML tag names | preset-tagify |
| Preset Rem to Px | Convert rem units to px for utilities | preset-rem-to-px |
Transformers
| Topic | Description | Reference |
|---|---|---|
| Variant Group | Shorthand for grouping utilities with common prefixes | transformer-variant-group |
| Directives | CSS directives: @apply, @screen, theme(), icon() | transformer-directives |
| Compile Class | Compile multiple classes into one hashed class | transformer-compile-class |
| Attributify JSX | Support valueless attributify in JSX/TSX | transformer-attributify-jsx |
Integrations
| Topic | Description | Reference |
|---|---|---|
| Vite Integration | Setting up UnoCSS with Vite and framework-specific tips | integrations-vite |
| Nuxt Integration | UnoCSS module for Nuxt applications | integrations-nuxt |
Generation Info
- Source:
sources/unocss - Git SHA:
2f7f267d0cc0c43d44357208aabb35b049359a08 - Generated: 2026-01-28
UnoCSS Configuration
UnoCSS is configured via a dedicated config file in your project root.
Config File
Recommended: Use a dedicated uno.config.ts file for best IDE support and HMR.
// uno.config.ts
import {
defineConfig,
presetAttributify,
presetIcons,
presetTypography,
presetWebFonts,
presetWind3,
transformerDirectives,
transformerVariantGroup
} from 'unocss'
export default defineConfig({
shortcuts: [
// ...
],
theme: {
colors: {
// ...
}
},
presets: [
presetWind3(),
presetAttributify(),
presetIcons(),
presetTypography(),
presetWebFonts({
fonts: {
// ...
},
}),
],
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
})UnoCSS automatically looks for uno.config.{js,ts,mjs,mts} or unocss.config.{js,ts,mjs,mts} in the project root.
Key Configuration Options
rules
Define CSS utility rules. Later entries have higher priority.
rules: [
['m-1', { margin: '0.25rem' }],
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
]shortcuts
Combine multiple rules into a single shorthand.
shortcuts: {
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
}theme
Theme object for design tokens shared between rules.
theme: {
colors: {
brand: '#942192',
},
breakpoints: {
sm: '640px',
md: '768px',
},
}presets
Predefined configurations bundling rules, variants, and themes.
presets: [
presetWind3(),
presetIcons(),
]transformers
Transform source code to support special syntax.
transformers: [
transformerDirectives(),
transformerVariantGroup(),
]variants
Preprocess selectors with ability to rewrite CSS output.
extractors
Handle source files and extract utility class names.
preflights
Inject raw CSS globally.
layers
Control the order of CSS layers. Default is 0.
layers: {
'components': -1,
'default': 1,
'utilities': 2,
}safelist
Utilities that are always included in output.
safelist: ['p-1', 'p-2', 'p-3']blocklist
Utilities that are always excluded.
blocklist: ['p-1', /^p-[2-4]$/]content
Configure where to extract utilities from.
content: {
pipeline: {
include: [/\.(vue|svelte|tsx|html)($|\?)/],
},
filesystem: ['src/**/*.php'],
}separators
Variant separator characters. Default: [':', '-']
outputToCssLayers
Output UnoCSS layers as CSS Cascade Layers.
outputToCssLayers: trueSpecifying Config File Location
// vite.config.ts
import UnoCSS from 'unocss/vite'
export default defineConfig({
plugins: [
UnoCSS({
configFile: '../my-uno.config.ts',
}),
],
})<!-- Source references:
- https://unocss.dev/guide/config-file
- https://unocss.dev/config/
-->
Extracting
UnoCSS searches for utility usages in your codebase and generates CSS on-demand.
Content Sources
Pipeline Extraction (Vite/Webpack)
Most efficient - extracts from build tool pipeline.
Default file types: .jsx, .tsx, .vue, .md, .html, .svelte, .astro, .marko
Not included by default: .js, .ts
export default defineConfig({
content: {
pipeline: {
include: [
/\.(vue|svelte|[jt]sx|mdx?|astro|html)($|\?)/,
'src/**/*.{js,ts}', // Add js/ts
],
},
},
})Filesystem Extraction
For files not in build pipeline:
export default defineConfig({
content: {
filesystem: [
'src/**/*.php',
'public/*.html',
],
},
})Inline Text Extraction
export default defineConfig({
content: {
inline: [
'<div class="p-4 text-red">Some text</div>',
async () => (await fetch('https://example.com')).text(),
],
},
})Magic Comments
@unocss-include
Force scan a file:
// @unocss-include
export const classes = {
active: 'bg-primary text-white',
}@unocss-ignore
Skip entire file:
// @unocss-ignore@unocss-skip-start / @unocss-skip-end
Skip specific blocks:
<p class="text-green">Extracted</p>
<!-- @unocss-skip-start -->
<p class="text-red">NOT extracted</p>
<!-- @unocss-skip-end -->Limitations
UnoCSS works at build time - dynamic classes don't work:
<!-- Won't work! -->
<div class="p-${size}"></div>Solutions
1. Safelist - Pre-generate known values:
safelist: ['p-1', 'p-2', 'p-3', 'p-4']2. Static mapping - List combinations statically:
const colors = {
red: 'text-red border-red',
blue: 'text-blue border-blue',
}3. Runtime - Use @unocss/runtime for true runtime generation.
Custom Extractors
extractors: [
{
name: 'my-extractor',
extract({ code }) {
return code.match(/class:[\w-]+/g) || []
},
},
]<!-- Source references:
- https://unocss.dev/guide/extracting
-->
Layers and Preflights
Control CSS output order and inject global CSS.
Layers
Set layer on rules:
rules: [
[/^m-(\d)$/, ([, d]) => ({ margin: `${d / 4}rem` }), { layer: 'utilities' }],
['btn', { padding: '4px' }], // default layer
]Layer Ordering
layers: {
'components': -1,
'default': 1,
'utilities': 2,
}Import Layers Separately
import 'uno:components.css'
import 'uno.css'
import './my-custom.css'
import 'uno:utilities.css'CSS Cascade Layers
outputToCssLayers: true
// Or with custom names
outputToCssLayers: {
cssLayerName: (layer) => {
if (layer === 'default') return 'utilities'
if (layer === 'shortcuts') return 'utilities.shortcuts'
}
}Layer Variants
<!-- UnoCSS layer -->
<p class="uno-layer-my-layer:text-xl">
<!-- CSS @layer -->
<p class="layer-my-layer:text-xl">Preflights
Inject raw CSS globally:
preflights: [
{
getCSS: ({ theme }) => `
* {
color: ${theme.colors.gray?.[700] ?? '#333'};
margin: 0;
}
`,
},
]With layer:
preflights: [
{
layer: 'base',
getCSS: () => `html { font-family: system-ui; }`,
},
]preset-wind4 Layers
| Layer | Description | Order |
|---|---|---|
properties | CSS @property rules | -200 |
theme | Theme CSS variables | -150 |
base | Reset styles | -100 |
<!-- Source references:
- https://unocss.dev/config/layers
- https://unocss.dev/config/preflights
-->
UnoCSS Rules
Rules define utility classes and the CSS they generate. UnoCSS has many built-in rules via presets and allows custom rules.
Static Rules
Simple mapping from class name to CSS properties:
rules: [
['m-1', { margin: '0.25rem' }],
['font-bold', { 'font-weight': 700 }],
]Usage: <div class="m-1"> generates .m-1 { margin: 0.25rem; }
Note: Use CSS property syntax with hyphens (e.g., font-weight not fontWeight). Quote properties with hyphens.
Dynamic Rules
Use RegExp matcher with function body for flexible utilities:
rules: [
// Match m-1, m-2, m-100, etc.
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
// Access theme and context
[/^p-(\d+)$/, (match, ctx) => ({ padding: `${match[1] / 4}rem` })],
]The function receives: 1. RegExp match result (destructure to get captured groups) 2. Context object with theme, symbols, etc.
CSS Fallback Values
Return 2D array for CSS property fallbacks (browser compatibility):
rules: [
[/^h-(\d+)dvh$/, ([_, d]) => [
['height', `${d}vh`],
['height', `${d}dvh`],
]],
]Generates: .h-100dvh { height: 100vh; height: 100dvh; }
Special Symbols
Control CSS output with symbols from @unocss/core:
import { symbols } from '@unocss/core'
rules: [
['grid', {
[symbols.parent]: '@supports (display: grid)',
display: 'grid',
}],
]Available Symbols
| Symbol | Description |
|---|---|
symbols.parent | Parent wrapper (e.g., @supports, @media) |
symbols.selector | Function to modify the selector |
symbols.layer | Set the UnoCSS layer |
symbols.variants | Array of variant handlers |
symbols.shortcutsNoMerge | Disable merging in shortcuts |
symbols.noMerge | Disable rule merging |
symbols.sort | Override sorting order |
symbols.body | Full control of CSS body |
Multi-Selector Rules
Use generator functions to yield multiple CSS rules:
rules: [
[/^button-(.*)$/, function* ([, color], { symbols }) {
yield { background: color }
yield {
[symbols.selector]: selector => `${selector}:hover`,
background: `color-mix(in srgb, ${color} 90%, black)`
}
}],
]Generates both .button-red { background: red; } and .button-red:hover { ... }
Fully Controlled Rules
Return a string for complete CSS control (advanced):
import { defineConfig, toEscapedSelector as e } from 'unocss'
rules: [
[/^custom-(.+)$/, ([, name], { rawSelector, theme }) => {
const selector = e(rawSelector)
return `
${selector} { font-size: ${theme.fontSize.sm}; }
${selector}::after { content: 'after'; }
@media (min-width: ${theme.breakpoints.sm}) {
${selector} { font-size: ${theme.fontSize.lg}; }
}
`
}],
]Warning: Fully controlled rules don't work with variants like hover:.
Symbols.body for Variant Support
Use symbols.body to keep variant support with custom CSS:
rules: [
['custom-red', {
[symbols.body]: `
font-size: 1rem;
&::after { content: 'after'; }
& > .bar { color: red; }
`,
[symbols.selector]: selector => `:is(${selector})`,
}]
]Rule Ordering
Later rules have higher priority. Dynamic rules output is sorted alphabetically within the group.
Rule Merging
UnoCSS merges rules with identical CSS bodies:
<div class="m-2 hover:m2">Generates:
.hover\:m2:hover, .m-2 { margin: 0.5rem; }Use symbols.noMerge to disable.
<!-- Source references:
- https://unocss.dev/config/rules
-->
Safelist and Blocklist
Control which utilities are always included or excluded.
Safelist
Utilities always included, regardless of detection:
export default defineConfig({
safelist: [
'p-1', 'p-2', 'p-3',
// Dynamic generation
...Array.from({ length: 4 }, (_, i) => `p-${i + 1}`),
],
})Function Form
safelist: [
'p-1',
() => ['m-1', 'm-2'],
(context) => {
const colors = Object.keys(context.theme.colors || {})
return colors.map(c => `bg-${c}-500`)
},
]Common Use Cases
safelist: [
// Dynamic colors from CMS
() => ['primary', 'secondary'].flatMap(c => [
`bg-${c}`, `text-${c}`, `border-${c}`,
]),
// Component variants
() => {
const variants = ['primary', 'danger']
const sizes = ['sm', 'md', 'lg']
return variants.flatMap(v => sizes.map(s => `btn-${v}-${s}`))
},
]Blocklist
Utilities never generated:
blocklist: [
'p-1', // Exact match
/^p-[2-4]$/, // Regex
]With Messages
blocklist: [
['bg-red-500', { message: 'Use bg-red-600 instead' }],
[/^text-xs$/, { message: 'Use text-sm for accessibility' }],
]Safelist vs Blocklist
| Feature | Safelist | Blocklist |
|---|---|---|
| Purpose | Always include | Always exclude |
| Strings | ✅ | ✅ |
| Regex | ❌ | ✅ |
| Functions | ✅ | ❌ |
Note: Blocklist wins if utility is in both.
Best Practice
Prefer static mappings over safelist:
// Better: UnoCSS extracts automatically
const sizes = {
sm: 'text-sm p-2',
md: 'text-base p-4',
}
// Avoid: Large safelist
safelist: ['text-sm', 'text-base', 'p-2', 'p-4']<!-- Source references:
- https://unocss.dev/config/safelist
- https://unocss.dev/guide/extracting
-->
UnoCSS Shortcuts
Shortcuts combine multiple rules into a single shorthand, inspired by Windi CSS.
Static Shortcuts
Define as an object mapping shortcut names to utility combinations:
shortcuts: {
// Multiple utilities combined
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
// Single utility alias
'red': 'text-red-100',
}Usage:
<button class="btn btn-green">Click me</button>Dynamic Shortcuts
Use RegExp matcher with function, similar to dynamic rules:
shortcuts: [
// Static shortcuts can be in array too
{
btn: 'py-2 px-4 font-semibold rounded-lg shadow-md',
},
// Dynamic shortcut
[/^btn-(.*)$/, ([, c]) => `bg-${c}-400 text-${c}-100 py-2 px-4 rounded-lg`],
]Now btn-green and btn-red generate:
.btn-green {
padding: 0.5rem 1rem;
--un-bg-opacity: 1;
background-color: rgb(74 222 128 / var(--un-bg-opacity));
border-radius: 0.5rem;
--un-text-opacity: 1;
color: rgb(220 252 231 / var(--un-text-opacity));
}Accessing Theme in Shortcuts
Dynamic shortcuts receive context with theme access:
shortcuts: [
[/^badge-(.*)$/, ([, c], { theme }) => {
if (Object.keys(theme.colors).includes(c))
return `bg-${c}4:10 text-${c}5 rounded`
}],
]Shortcuts Layer
Shortcuts are output to the shortcuts layer by default. Configure with:
shortcutsLayer: 'my-shortcuts-layer'Key Points
- Later shortcuts have higher priority
- Shortcuts can reference other shortcuts
- Dynamic shortcuts work like dynamic rules
- Shortcuts are expanded at build time, not runtime
- All variants work with shortcuts (
hover:btn,dark:btn, etc.)
<!-- Source references:
- https://unocss.dev/config/shortcuts
-->
UnoCSS Theme
UnoCSS supports theming similar to Tailwind CSS / Windi CSS. The theme property is deep-merged with the default theme.
Basic Usage
theme: {
colors: {
veryCool: '#0000ff', // class="text-very-cool"
brand: {
primary: 'hsl(var(--hue, 217) 78% 51%)', // class="bg-brand-primary"
DEFAULT: '#942192' // class="bg-brand"
},
},
}Using Theme in Rules
Access theme values in dynamic rules:
rules: [
[/^text-(.*)$/, ([, c], { theme }) => {
if (theme.colors[c])
return { color: theme.colors[c] }
}],
]Using Theme in Variants
variants: [
{
name: 'variant-name',
match(matcher, { theme }) {
// Access theme.breakpoints, theme.colors, etc.
},
},
]Using Theme in Shortcuts
shortcuts: [
[/^badge-(.*)$/, ([, c], { theme }) => {
if (Object.keys(theme.colors).includes(c))
return `bg-${c}4:10 text-${c}5 rounded`
}],
]Breakpoints
Warning: Custom breakpoints object overrides the default, not merges.
theme: {
breakpoints: {
sm: '320px',
md: '640px',
},
}Only sm: and md: variants will be available.
Inherit Default Breakpoints
Use extendTheme to merge with defaults:
extendTheme: (theme) => {
return {
...theme,
breakpoints: {
...theme.breakpoints,
sm: '320px',
md: '640px',
},
}
}Note: verticalBreakpoints works the same for vertical layout.
Breakpoint Sorting
Breakpoints are sorted by size. Use consistent units to avoid errors:
theme: {
breakpoints: {
sm: '320px',
// Don't mix units - convert rem to px
// md: '40rem', // Bad
md: `${40 * 16}px`, // Good
lg: '960px',
},
}ExtendTheme
extendTheme lets you modify the merged theme object:
Mutate Theme
extendTheme: (theme) => {
theme.colors.veryCool = '#0000ff'
theme.colors.brand = {
primary: 'hsl(var(--hue, 217) 78% 51%)',
}
}Replace Theme
Return a new object to completely replace:
extendTheme: (theme) => {
return {
...theme,
colors: {
...theme.colors,
veryCool: '#0000ff',
},
}
}Theme Differences in Presets
preset-wind3 vs preset-wind4
| preset-wind3 | preset-wind4 |
|---|---|
fontFamily | font |
fontSize | text.fontSize |
lineHeight | text.lineHeight or leading |
letterSpacing | text.letterSpacing or tracking |
borderRadius | radius |
easing | ease |
breakpoints | breakpoint |
boxShadow | shadow |
transitionProperty | property |
Common Theme Keys
colors- Color palettebreakpoints- Responsive breakpointsfontFamily- Font stacksfontSize- Text sizesspacing- Spacing scaleborderRadius- Border radius valuesboxShadow- Shadow definitionsanimation- Animation keyframes and timing
<!-- Source references:
- https://unocss.dev/config/theme
-->
UnoCSS Variants
Variants apply modifications to utility rules, like hover:, dark:, or responsive prefixes.
How Variants Work
When matching hover:m-2:
1. hover:m-2 is extracted from source 2. Sent to all variants for matching 3. hover: variant matches and returns m-2 4. Result m-2 continues to next variants 5. Finally matches the rule .m-2 { margin: 0.5rem; } 6. Variant transformation applied: .hover\:m-2:hover { margin: 0.5rem; }
Creating Custom Variants
variants: [
// hover: variant
(matcher) => {
if (!matcher.startsWith('hover:'))
return matcher
return {
// Remove prefix, pass to next variants/rules
matcher: matcher.slice(6),
// Modify the selector
selector: s => `${s}:hover`,
}
},
],
rules: [
[/^m-(\d)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
]Variant Return Object
matcher- The processed class name to pass forwardselector- Function to customize the CSS selectorparent- Wrapper like@media,@supportslayer- Specify output layersort- Control ordering
Built-in Variants (preset-wind3)
Pseudo-classes
hover:,focus:,active:,visited:first:,last:,odd:,even:disabled:,checked:,required:focus-within:,focus-visible:
Pseudo-elements
before:,after:placeholder:,selection:marker:,file:
Responsive
sm:,md:,lg:,xl:,2xl:lt-sm:(less than sm)at-lg:(at lg only)
Dark Mode
dark:- Class-based dark mode (default)@dark:- Media query dark mode
Group/Peer
group-hover:,group-focus:peer-checked:,peer-focus:
Container Queries
@container,@sm:,@md:
print:
Supports
supports-[display:grid]:
Aria
aria-checked:,aria-disabled:
Data Attributes
data-[state=open]:
Dark Mode Configuration
Class-based (default)
presetWind3({
dark: 'class'
})<div class="dark:bg-gray-800">Generates: .dark .dark\:bg-gray-800 { ... }
Media Query
presetWind3({
dark: 'media'
})Generates: @media (prefers-color-scheme: dark) { ... }
Opt-in Media Query
Use @dark: regardless of config:
<div class="@dark:bg-gray-800">Custom Selectors
presetWind3({
dark: {
light: '.light-mode',
dark: '.dark-mode',
}
})CSS @layer Variant
Native CSS @layer support:
<div class="layer-foo:p-4" />Generates:
@layer foo {
.layer-foo\:p-4 { padding: 1rem; }
}Breakpoint Differences from Windi CSS
| Windi CSS | UnoCSS |
|---|---|
<sm:p-1 | lt-sm:p-1 |
@lg:p-1 | at-lg:p-1 |
>xl:p-1 | xl:p-1 |
Media Hover (Experimental)
Addresses sticky hover on touch devices:
<div class="@hover-text-red">Generates:
@media (hover: hover) and (pointer: fine) {
.\@hover-text-red:hover { color: rgb(248 113 113); }
}<!-- Source references:
- https://unocss.dev/config/variants
- https://unocss.dev/presets/wind3
- https://unocss.dev/presets/mini
-->
UnoCSS Nuxt Integration
The official Nuxt module for UnoCSS.
Installation
pnpm add -D unocss @unocss/nuxtAdd to Nuxt config:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
],
})Create config file:
// uno.config.ts
import { defineConfig, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
],
})Note: The uno.css entry is automatically injected by the module.
Support Status
| Build Tool | Nuxt 2 | Nuxt Bridge | Nuxt 3 |
|---|---|---|---|
| Webpack Dev | ✅ | ✅ | 🚧 |
| Webpack Build | ✅ | ✅ | ✅ |
| Vite Dev | - | ✅ | ✅ |
| Vite Build | - | ✅ | ✅ |
Configuration
Using uno.config.ts (Recommended)
Use a dedicated config file for best IDE support:
// uno.config.ts
import { defineConfig, presetWind3, presetIcons } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetIcons(),
],
shortcuts: {
'btn': 'py-2 px-4 font-semibold rounded-lg',
},
})Nuxt Layers Support
Enable automatic config merging from Nuxt layers:
// nuxt.config.ts
export default defineNuxtConfig({
unocss: {
nuxtLayers: true,
},
})Then in your root config:
// uno.config.ts
import config from './.nuxt/uno.config.mjs'
export default configOr extend the merged config:
// uno.config.ts
import { mergeConfigs } from '@unocss/core'
import config from './.nuxt/uno.config.mjs'
export default mergeConfigs([config, {
// Your overrides
shortcuts: {
'custom': 'text-red-500',
},
}])Common Setup Example
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
],
})// uno.config.ts
import {
defineConfig,
presetAttributify,
presetIcons,
presetTypography,
presetWebFonts,
presetWind3,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetAttributify(),
presetIcons({
scale: 1.2,
}),
presetTypography(),
presetWebFonts({
fonts: {
sans: 'DM Sans',
mono: 'DM Mono',
},
}),
],
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
shortcuts: [
['btn', 'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
],
})Usage in Components
<template>
<div class="p-4 text-center">
<h1 class="text-3xl font-bold text-blue-600">
Hello UnoCSS!
</h1>
<button class="btn mt-4">
Click me
</button>
</div>
</template>With attributify mode:
<template>
<div p="4" text="center">
<h1 text="3xl blue-600" font="bold">
Hello UnoCSS!
</h1>
</div>
</template>Inspector
In development, visit /_nuxt/__unocss to access the UnoCSS inspector.
Key Differences from Vite
- No need to import
virtual:uno.css- automatically injected - Config file discovery works the same
- All Vite plugin features available
- Nuxt layers config merging available
<!-- Source references:
- https://unocss.dev/integrations/nuxt
-->
UnoCSS Vite Integration
The Vite plugin is the most common way to use UnoCSS.
Installation
pnpm add -D unocss// vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UnoCSS(),
],
})Create config file:
// uno.config.ts
import { defineConfig, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
],
})Add to entry:
// main.ts
import 'virtual:uno.css'Modes
global (default)
Standard mode - generates global CSS injected via uno.css import.
import 'virtual:uno.css'vue-scoped
Injects generated CSS into Vue SFC <style scoped>.
UnoCSS({
mode: 'vue-scoped',
})shadow-dom
For Web Components using Shadow DOM:
UnoCSS({
mode: 'shadow-dom',
})Add placeholder in component styles:
const template = document.createElement('template')
template.innerHTML = `
<style>
:host { ... }
@unocss-placeholder
</style>
<div class="m-1em">...</div>
`per-module (experimental)
Generates CSS per module with optional scoping.
dist-chunk (experimental)
Generates CSS per chunk on build for MPA.
DevTools Support
Edit classes directly in browser DevTools:
import 'virtual:uno.css'
import 'virtual:unocss-devtools'Warning: Uses MutationObserver to detect changes. Dynamic classes from scripts will also be included.
Framework-Specific Setup
React
// vite.config.ts
import React from '@vitejs/plugin-react'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS(), // Must be before React when using attributify
React(),
],
}Note: Remove tsc from build script if using @unocss/preset-attributify.
Vue
Works out of the box with @vitejs/plugin-vue.
Svelte
import { svelte } from '@sveltejs/vite-plugin-svelte'
import extractorSvelte from '@unocss/extractor-svelte'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS({
extractors: [extractorSvelte()],
}),
svelte(),
],
}Supports class:foo and class:foo={bar} syntax.
SvelteKit
Same as Svelte, use sveltekit() from @sveltejs/kit/vite.
Solid
import UnoCSS from 'unocss/vite'
import solidPlugin from 'vite-plugin-solid'
export default {
plugins: [
UnoCSS(),
solidPlugin(),
],
}Preact
import Preact from '@preact/preset-vite'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS(),
Preact(),
],
}Elm
import Elm from 'vite-plugin-elm'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
Elm(),
UnoCSS(),
],
}Web Components (Lit)
UnoCSS({
mode: 'shadow-dom',
shortcuts: [
{ 'cool-blue': 'bg-blue-500 text-white' },
],
})// my-element.ts
@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
:host { ... }
@unocss-placeholder
`
}Supports part-[<part-name>]:<utility> for ::part styling.
Inspector
Visit http://localhost:5173/__unocss in dev mode to:
- Inspect generated CSS rules
- See applied classes per file
- Test utilities in REPL
Legacy Browser Support
With @vitejs/plugin-legacy:
import legacy from '@vitejs/plugin-legacy'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS({
legacy: {
renderModernChunks: false,
},
}),
legacy({
targets: ['defaults', 'not IE 11'],
renderModernChunks: false,
}),
],
}VanillaJS / TypeScript
By default, .js and .ts files are not extracted. Configure to include:
// uno.config.ts
export default defineConfig({
content: {
pipeline: {
include: [
/\.(vue|svelte|[jt]sx|html)($|\?)/,
'src/**/*.{js,ts}',
],
},
},
})Or use magic comment in files:
// @unocss-include
export const classes = {
active: 'bg-primary text-white',
}<!-- Source references:
- https://unocss.dev/integrations/vite
-->
Preset Attributify
Group utilities in HTML attributes for better readability.
Installation
import { defineConfig, presetAttributify, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetAttributify(),
],
})Basic Usage
Instead of long class strings:
<button class="bg-blue-400 hover:bg-blue-500 text-sm text-white font-mono font-light py-2 px-4 rounded border-2 border-blue-200">
Button
</button>Group by prefix in attributes:
<button
bg="blue-400 hover:blue-500"
text="sm white"
font="mono light"
p="y-2 x-4"
border="2 rounded blue-200"
>
Button
</button>Prefix Self-Referencing
For utilities matching their prefix (flex, grid, border), use ~:
<!-- Before -->
<button class="border border-red">Button</button>
<!-- After -->
<button border="~ red">Button</button>Valueless Attributify
Use utilities as boolean attributes:
<div m-2 rounded text-teal-400 />Handling Property Conflicts
When attribute names conflict with HTML properties:
<!-- Use un- prefix -->
<a un-text="red">Text color to red</a>Enforce Prefix
presetAttributify({
prefix: 'un-',
prefixedOnly: true,
})Options
presetAttributify({
strict: false, // Only generate CSS for attributify
prefix: 'un-', // Attribute prefix
prefixedOnly: false, // Require prefix for all
nonValuedAttribute: true, // Support valueless attributes
ignoreAttributes: [], // Attributes to ignore
trueToNonValued: false, // Treat value="true" as valueless
})TypeScript Support
Vue 3
// html.d.ts
declare module '@vue/runtime-dom' {
interface HTMLAttributes { [key: string]: any }
}
declare module '@vue/runtime-core' {
interface AllowedComponentProps { [key: string]: any }
}
export {}React
import type { AttributifyAttributes } from '@unocss/preset-attributify'
declare module 'react' {
interface HTMLAttributes<T> extends AttributifyAttributes {}
}JSX Support
For JSX where <div foo> becomes <div foo={true}>:
import { transformerAttributifyJsx } from 'unocss'
export default defineConfig({
transformers: [
transformerAttributifyJsx(),
],
})Important: Only use attributify if uno.config.* shows presetAttributify() is enabled.
<!-- Source references:
- https://unocss.dev/presets/attributify
-->
Preset Icons
Use any icon as a pure CSS class, powered by Iconify.
Installation
pnpm add -D @unocss/preset-icons @iconify-json/[collection-name]Example: @iconify-json/mdi for Material Design Icons, @iconify-json/carbon for Carbon icons.
import { defineConfig, presetIcons } from 'unocss'
export default defineConfig({
presets: [
presetIcons(),
],
})Usage
Two naming conventions:
<prefix><collection>-<icon>→i-ph-anchor-simple-thin<prefix><collection>:<icon>→i-ph:anchor-simple-thin
<!-- Phosphor anchor icon -->
<div class="i-ph-anchor-simple-thin" />
<!-- Material Design alarm with color -->
<div class="i-mdi-alarm text-orange-400" />
<!-- Large Vue logo -->
<div class="i-logos-vue text-3xl" />
<!-- Dynamic: Sun in light mode, Moon in dark -->
<button class="i-carbon-sun dark:i-carbon-moon" />
<!-- Hover effect -->
<div class="i-twemoji-grinning-face-with-smiling-eyes hover:i-twemoji-face-with-tears-of-joy" />Browse icons at icones.js.org or Iconify.
Icon Modes
Icons automatically choose between mask (monochrome) and background-img (colorful).
Force Specific Mode
?mask- Render as mask (colorable withcurrentColor)?bg- Render as background image (preserves original colors)
<!-- Original with colors -->
<div class="i-vscode-icons:file-type-light-pnpm" />
<!-- Force mask mode, apply custom color -->
<div class="i-vscode-icons:file-type-light-pnpm?mask text-red-300" />Options
presetIcons({
scale: 1.2, // Scale relative to font size
prefix: 'i-', // Class prefix (default)
mode: 'auto', // 'auto' | 'mask' | 'bg'
extraProperties: {
'display': 'inline-block',
'vertical-align': 'middle',
},
warn: true, // Warn on missing icons
autoInstall: true, // Auto-install missing icon sets
cdn: 'https://esm.sh/', // CDN for browser usage
})Custom Icon Collections
Inline SVGs
presetIcons({
collections: {
custom: {
circle: '<svg viewBox="0 0 120 120"><circle cx="60" cy="60" r="50"></circle></svg>',
},
}
})Usage: <span class="i-custom:circle"></span>
File System Loader
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'
presetIcons({
collections: {
'my-icons': FileSystemIconLoader(
'./assets/icons',
svg => svg.replace(/#fff/, 'currentColor')
),
}
})Dynamic Import (Browser)
import presetIcons from '@unocss/preset-icons/browser'
presetIcons({
collections: {
carbon: () => import('@iconify-json/carbon/icons.json').then(i => i.default),
}
})Icon Customization
presetIcons({
customizations: {
// Transform SVG
transform(svg, collection, icon) {
return svg.replace(/#fff/, 'currentColor')
},
// Global sizing
customize(props) {
props.width = '2em'
props.height = '2em'
return props
},
// Per-collection
iconCustomizer(collection, icon, props) {
if (collection === 'mdi') {
props.width = '2em'
}
}
}
})CSS Directive
Use icon() in CSS (requires transformer-directives):
.icon {
background-image: icon('i-carbon-sun');
}
.icon-colored {
background-image: icon('i-carbon-moon', '#fff');
}Accessibility
<!-- With label -->
<a href="/profile" aria-label="Profile" class="i-ph:user-duotone"></a>
<!-- Decorative -->
<a href="/profile">
<span aria-hidden="true" class="i-ph:user-duotone"></span>
My Profile
</a><!-- Source references:
- https://unocss.dev/presets/icons
-->
Preset Mini
The minimal preset with only essential rules and variants. Good starting point for custom presets.
Installation
import { defineConfig, presetMini } from 'unocss'
export default defineConfig({
presets: [
presetMini(),
],
})What's Included
Subset of preset-wind3 with essential utilities aligned to CSS properties:
- Basic spacing (margin, padding)
- Display (flex, grid, block, etc.)
- Positioning (absolute, relative, fixed)
- Sizing (width, height)
- Colors (text, background, border)
- Typography basics (font-size, font-weight)
- Borders and border-radius
- Basic transforms and transitions
What's NOT Included
Opinionated or complex Tailwind utilities:
container- Complex animations
- Gradients
- Advanced typography
- Prose classes
Use Cases
1. Building custom presets - Start with mini and add only what you need 2. Minimal bundle size - When you only need basic utilities 3. Learning - Understand UnoCSS core without Tailwind complexity
Dark Mode
Same as preset-wind3:
presetMini({
dark: 'class' // or 'media'
})<div class="dark:bg-red:10" />Class-based:
.dark .dark\:bg-red\:10 {
background-color: rgb(248 113 113 / 0.1);
}Media query:
@media (prefers-color-scheme: dark) {
.dark\:bg-red\:10 {
background-color: rgb(248 113 113 / 0.1);
}
}CSS @layer Variant
Native CSS layer support:
<div class="layer-foo:p4" />@layer foo {
.layer-foo\:p4 {
padding: 1rem;
}
}Theme Customization
presetMini({
theme: {
colors: {
veryCool: '#0000ff',
brand: {
primary: 'hsl(var(--hue, 217) 78% 51%)',
}
},
}
})Note: breakpoints property is overridden, not merged.
Options
presetMini({
// Dark mode: 'class' | 'media' | { light: string, dark: string }
dark: 'class',
// Generate [group=""] instead of .group for attributify
attributifyPseudo: false,
// CSS variable prefix (default: 'un-')
variablePrefix: 'un-',
// Utility prefix
prefix: undefined,
// Preflight generation: true | false | 'on-demand'
preflight: true,
})Building on Mini
Create custom preset extending mini:
import { presetMini } from 'unocss'
import type { Preset } from 'unocss'
export const myPreset: Preset = {
name: 'my-preset',
presets: [presetMini()],
rules: [
// Add custom rules
['card', { 'border-radius': '8px', 'box-shadow': '0 2px 8px rgba(0,0,0,0.1)' }],
],
shortcuts: {
'btn': 'px-4 py-2 rounded bg-blue-500 text-white',
},
}<!-- Source references:
- https://unocss.dev/presets/mini
-->
Preset Rem to Px
Converts rem units to px in generated utilities.
Installation
import { defineConfig, presetRemToPx, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetRemToPx(),
],
})What It Does
Transforms all rem values to px:
<div class="p-4">Without preset:
.p-4 { padding: 1rem; }With preset:
.p-4 { padding: 16px; }Use Cases
- Projects requiring pixel-perfect designs
- Environments where rem doesn't work well
- Consistency with pixel-based design systems
- Email templates (better compatibility)
Options
presetRemToPx({
// Base font size for conversion (default: 16)
baseFontSize: 16,
})Custom base:
presetRemToPx({
baseFontSize: 14, // 1rem = 14px
})With Preset Wind4
Note: presetRemToPx is not needed with preset-wind4. Use the built-in processor instead:
import { createRemToPxProcessor } from '@unocss/preset-wind4/utils'
export default defineConfig({
presets: [
presetWind4({
preflights: {
theme: {
process: createRemToPxProcessor(),
}
},
}),
],
// Also apply to utilities
postprocess: [createRemToPxProcessor()],
})Important Notes
- Order matters: place after the preset that generates rem values
- Affects all utilities with rem units
- Theme values in rem are also converted
<!-- Source references:
- https://unocss.dev/presets/rem-to-px
- https://unocss.dev/presets/wind4
-->
Preset Tagify
Use CSS utilities directly as HTML tag names.
Installation
import { defineConfig, presetTagify } from 'unocss'
export default defineConfig({
presets: [
presetTagify(),
],
})Basic Usage
Instead of:
<span class="text-red">red text</span>
<div class="flex">flexbox</div>
<span class="i-line-md-emoji-grin"></span>Use tag names directly:
<text-red>red text</text-red>
<flex>flexbox</flex>
<i-line-md-emoji-grin />Works exactly the same!
With Prefix
presetTagify({
prefix: 'un-'
})<!-- Matched -->
<un-flex></un-flex>
<!-- Not matched -->
<flex></flex>Extra Properties
Add CSS properties to matched tags:
presetTagify({
// Add display: inline-block to icons
extraProperties: matched => matched.startsWith('i-')
? { display: 'inline-block' }
: {},
})Or apply to all:
presetTagify({
extraProperties: { display: 'block' }
})Options
presetTagify({
// Tag prefix
prefix: '',
// Excluded tags (won't be processed)
excludedTags: ['b', /^h\d+$/, 'table'],
// Extra CSS properties
extraProperties: {},
// Enable default extractor
defaultExtractor: true,
})Excluded Tags
By default, these tags are excluded:
b(bold)h1throughh6(headings)table
Add your own:
presetTagify({
excludedTags: [
'b',
/^h\d+$/,
'table',
'article', // Add custom exclusions
/^my-/, // Exclude tags starting with 'my-'
],
})Use Cases
- Quick prototyping
- Cleaner HTML for simple pages
- Icon embedding:
<i-carbon-sun /> - Semantic-like styling:
<flex-center>,<text-red>
Limitations
- Custom element names must contain a hyphen (HTML spec)
- Some frameworks may not support all custom elements
- Utilities without hyphens need the prefix option
<!-- Source references:
- https://unocss.dev/presets/tagify
-->
Preset Typography
Prose classes for adding typographic defaults to vanilla HTML content.
Installation
import { defineConfig, presetTypography, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(), // Required!
presetTypography(),
],
})Basic Usage
<article class="prose">
<h1>My Article</h1>
<p>This is styled with typographic defaults...</p>
</article>Sizes
<article class="prose prose-sm">Small</article>
<article class="prose prose-base">Base (default)</article>
<article class="prose prose-lg">Large</article>
<article class="prose prose-xl">Extra large</article>
<article class="prose prose-2xl">2X large</article>Responsive:
<article class="prose prose-sm md:prose-base lg:prose-lg">
Responsive typography
</article>Colors
<article class="prose prose-gray">Gray (default)</article>
<article class="prose prose-slate">Slate</article>
<article class="prose prose-blue">Blue</article>Dark Mode
<article class="prose dark:prose-invert">
Dark mode typography
</article>Excluding Elements
<article class="prose">
<p>Styled</p>
<div class="not-prose">
<p>NOT styled</p>
</div>
</article>Note: not-prose only works as a class.
Options
presetTypography({
selectorName: 'prose', // Custom selector
cssVarPrefix: '--un-prose', // CSS variable prefix
important: false, // Make !important
cssExtend: {
'code': { color: '#8b5cf6' },
'a:hover': { color: '#f43f5e' },
},
})<!-- Source references:
- https://unocss.dev/presets/typography
-->
Preset Web Fonts
Easily use web fonts from Google Fonts and other providers.
Installation
import { defineConfig, presetWebFonts, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetWebFonts({
provider: 'google',
fonts: {
sans: 'Roboto',
mono: 'Fira Code',
},
}),
],
})Providers
google- Google Fonts (default)bunny- Privacy-friendly alternativefontshare- Quality fonts by ITFfontsource- Self-hosted open source fontscoollabs- Privacy-friendly drop-in replacementnone- Treat as system font
Font Configuration
fonts: {
// Simple
sans: 'Roboto',
// Multiple (fallback)
mono: ['Fira Code', 'Fira Mono:400,700'],
// Detailed
lato: [
{
name: 'Lato',
weights: ['400', '700'],
italic: true,
},
{
name: 'sans-serif',
provider: 'none',
},
],
}Usage
<p class="font-sans">Roboto</p>
<code class="font-mono">Fira Code</code>Local Fonts
Self-host fonts:
import { createLocalFontProcessor } from '@unocss/preset-web-fonts/local'
presetWebFonts({
provider: 'none',
fonts: { sans: 'Roboto' },
processors: createLocalFontProcessor({
cacheDir: 'node_modules/.cache/unocss/fonts',
fontAssetsDir: 'public/assets/fonts',
fontServeBaseUrl: '/assets/fonts',
})
})<!-- Source references:
- https://unocss.dev/presets/web-fonts
-->
Preset Wind3
The Tailwind CSS / Windi CSS compatible preset. Most commonly used preset for UnoCSS.
Installation
import { defineConfig, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
],
})Note: @unocss/preset-uno and @unocss/preset-wind are deprecated and renamed to @unocss/preset-wind3.
Features
- Full Tailwind CSS v3 compatibility
- Dark mode (
dark:,@dark:) - All responsive variants (
sm:,md:,lg:,xl:,2xl:) - All standard utilities (flex, grid, spacing, colors, typography, etc.)
- Animation support (includes Animate.css animations)
Dark Mode
Class-based (default)
<div class="dark:bg-gray-800">Generates: .dark .dark\:bg-gray-800 { ... }
Media Query Based
presetWind3({
dark: 'media'
})Generates: @media (prefers-color-scheme: dark) { ... }
Opt-in Media Query
Use @dark: regardless of config:
<div class="@dark:bg-gray-800">Options
presetWind3({
// Dark mode strategy
dark: 'class', // 'class' | 'media' | { light: '.light', dark: '.dark' }
// Generate pseudo selector as [group=""] instead of .group
attributifyPseudo: false,
// CSS custom properties prefix
variablePrefix: 'un-',
// Utils prefix
prefix: '',
// Generate preflight CSS
preflight: true, // true | false | 'on-demand'
// Mark all utilities as !important
important: false, // boolean | string (selector)
})Important Option
Make all utilities !important:
presetWind3({
important: true,
})Or scope with selector to increase specificity without !important:
presetWind3({
important: '#app',
})Output: #app :is(.dark .dark\:bg-blue) { ... }
Differences from Tailwind CSS
Quotes Not Supported
Template quotes don't work due to extractor:
<!-- Won't work -->
<div class="before:content-['']">
<!-- Use shortcut instead -->
<div class="before:content-empty">Background Position
Use position: prefix for custom values:
<!-- Tailwind -->
<div class="bg-[center_top_1rem]">
<!-- UnoCSS -->
<div class="bg-[position:center_top_1rem]">Animations
UnoCSS integrates Animate.css. Use -alt suffix for Animate.css versions when names conflict:
animate-bounce- Tailwind versionanimate-bounce-alt- Animate.css version
Custom animations:
theme: {
animation: {
keyframes: {
custom: '{0%, 100% { opacity: 0; } 50% { opacity: 1; }}',
},
durations: {
custom: '1s',
},
timingFns: {
custom: 'ease-in-out',
},
counts: {
custom: 'infinite',
},
}
}Differences from Windi CSS
| Windi CSS | UnoCSS |
|---|---|
<sm:p-1 | lt-sm:p-1 |
@lg:p-1 | at-lg:p-1 |
>xl:p-1 | xl:p-1 |
Bracket syntax uses _ instead of ,:
<!-- Windi CSS -->
<div class="grid-cols-[1fr,10px,max-content]">
<!-- UnoCSS -->
<div class="grid-cols-[1fr_10px_max-content]">Experimental: Media Hover
Addresses sticky hover on touch devices:
<div class="@hover-text-red">Generates:
@media (hover: hover) and (pointer: fine) {
.\@hover-text-red:hover { ... }
}<!-- Source references:
- https://unocss.dev/presets/wind3
-->
Preset Wind4
The Tailwind CSS v4 compatible preset. Enhances preset-wind3 with modern CSS features.
Installation
import { defineConfig, presetWind4 } from 'unocss'
export default defineConfig({
presets: [
presetWind4(),
],
})Key Differences from Wind3
Built-in CSS Reset
No need for @unocss/reset - reset is built-in:
// Remove these imports
import '@unocss/reset/tailwind.css' // ❌ Not needed
import '@unocss/reset/tailwind-compat.css' // ❌ Not needed
// Enable in config
presetWind4({
preflights: {
reset: true,
},
})OKLCH Color Model
Uses oklch for better color perception and contrast. Not compatible with presetLegacyCompat.
Theme CSS Variables
Automatically generates CSS variables from theme:
:root, :host {
--spacing: 0.25rem;
--font-sans: ui-sans-serif, system-ui, sans-serif;
--colors-black: #000;
--colors-white: #fff;
/* ... */
}@property CSS Rules
Uses @property for better browser optimization:
@property --un-text-opacity {
syntax: '<percentage>';
inherits: false;
initial-value: 100%;
}Theme Key Changes
| preset-wind3 | preset-wind4 |
|---|---|
fontFamily | font |
fontSize | text.fontSize |
lineHeight | text.lineHeight or leading |
letterSpacing | text.letterSpacing or tracking |
borderRadius | radius |
easing | ease |
breakpoints | breakpoint |
verticalBreakpoints | verticalBreakpoint |
boxShadow | shadow |
transitionProperty | property |
container.maxWidth | containers.maxWidth |
Size properties (width, height, etc.) | Unified to spacing |
Options
presetWind4({
preflights: {
// Built-in reset styles
reset: true,
// Theme CSS variables generation
theme: 'on-demand', // true | false | 'on-demand'
// @property CSS rules
property: true,
},
})Theme Variable Processing
Convert rem to px for theme variables:
import { createRemToPxProcessor } from '@unocss/preset-wind4/utils'
presetWind4({
preflights: {
theme: {
mode: 'on-demand',
process: createRemToPxProcessor(),
}
},
})
// Also apply to utilities
export default defineConfig({
postprocess: [createRemToPxProcessor()],
})Property Layer Customization
presetWind4({
preflights: {
property: {
// Custom parent wrapper
parent: '@layer custom-properties',
// Custom selector
selector: ':where(*, ::before, ::after)',
},
},
})Remove @supports wrapper:
presetWind4({
preflights: {
property: {
parent: false,
},
},
})Generated Layers
| Layer | Description | Order |
|---|---|---|
properties | CSS @property rules | -200 |
theme | Theme CSS variables | -150 |
base | Reset/preflight styles | -100 |
Theme.defaults
Global default configuration for reset styles:
import type { Theme } from '@unocss/preset-wind4/theme'
const defaults: Theme['default'] = {
transition: {
duration: '150ms',
timingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
},
font: {
family: 'var(--font-sans)',
featureSettings: 'var(--font-sans--font-feature-settings)',
variationSettings: 'var(--font-sans--font-variation-settings)',
},
monoFont: {
family: 'var(--font-mono)',
// ...
},
}Compatibility Notes
presetRemToPx
Not needed - use built-in processor instead:
presetWind4({
preflights: {
theme: {
process: createRemToPxProcessor(),
}
},
})presetLegacyCompat
Not compatible with preset-wind4 due to oklch color model.
Migration from Wind3
1. Update theme keys according to the table above 2. Remove @unocss/reset imports 3. Enable preflights.reset: true 4. Test color outputs (oklch vs rgb) 5. Update any custom theme extensions
// Before (wind3)
theme: {
fontFamily: { sans: 'Roboto' },
fontSize: { lg: '1.125rem' },
breakpoints: { sm: '640px' },
}
// After (wind4)
theme: {
font: { sans: 'Roboto' },
text: { lg: { fontSize: '1.125rem' } },
breakpoint: { sm: '640px' },
}When to Use Wind4
Choose preset-wind4 when:
- Starting a new project
- Targeting modern browsers
- Want built-in reset and CSS variables
- Following Tailwind v4 conventions
Choose preset-wind3 when:
- Need legacy browser support
- Migrating from Tailwind v3
- Using presetLegacyCompat
- Want stable, proven preset
<!-- Source references:
- https://unocss.dev/presets/wind4
-->
Transformer Attributify JSX
Fixes valueless attributify mode in JSX where <div foo> becomes <div foo={true}>.
The Problem
In JSX, valueless attributes are transformed:
// You write
<div m-2 rounded text-teal-400 />
// JSX compiles to
<div m-2={true} rounded={true} text-teal-400={true} />The ={true} breaks UnoCSS attributify detection.
Installation
import {
defineConfig,
presetAttributify,
transformerAttributifyJsx
} from 'unocss'
export default defineConfig({
presets: [
presetAttributify(),
],
transformers: [
transformerAttributifyJsx(),
],
})How It Works
The transformer converts JSX boolean attributes back to strings:
// Input (after JSX compilation)
<div m-2={true} rounded={true} />
// Output (transformed)
<div m-2="" rounded="" />Now UnoCSS can properly extract the attributify classes.
Options
transformerAttributifyJsx({
// Only transform specific attributes
// Default: transforms all that match attributify patterns
blocklist: ['text', 'font'],
})When to Use
Required when using:
- React
- Preact
- Solid
- Any JSX-based framework
With valueless attributify syntax:
// This needs the transformer
<div flex items-center gap-4 />
// This works without transformer (has values)
<div flex="~" items="center" gap="4" />Framework Setup
React
// vite.config.ts
import React from '@vitejs/plugin-react'
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS(), // Must be before React
React(),
],
}// uno.config.ts
import {
defineConfig,
presetAttributify,
presetWind3,
transformerAttributifyJsx
} from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetAttributify(),
],
transformers: [
transformerAttributifyJsx(),
],
})Preact
Same as React, use @preact/preset-vite or @prefresh/vite.
Solid
import UnoCSS from 'unocss/vite'
import solidPlugin from 'vite-plugin-solid'
export default {
plugins: [
UnoCSS(),
solidPlugin(),
],
}TypeScript Support
Add type declarations:
// shims.d.ts
import type { AttributifyAttributes } from '@unocss/preset-attributify'
declare module 'react' {
interface HTMLAttributes<T> extends AttributifyAttributes {}
}<!-- Source references:
- https://unocss.dev/transformers/attributify-jsx
-->
Transformer Compile Class
Compiles multiple utility classes into a single hashed class for smaller HTML.
Installation
import { defineConfig, transformerCompileClass } from 'unocss'
export default defineConfig({
transformers: [
transformerCompileClass(),
],
})Usage
Add :uno: prefix to mark classes for compilation:
<!-- Before -->
<div class=":uno: text-center sm:text-left">
<div class=":uno: text-sm font-bold hover:text-red" />
</div>
<!-- After -->
<div class="uno-qlmcrp">
<div class="uno-0qw2gr" />
</div>Generated CSS
.uno-qlmcrp {
text-align: center;
}
.uno-0qw2gr {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 700;
}
.uno-0qw2gr:hover {
--un-text-opacity: 1;
color: rgb(248 113 113 / var(--un-text-opacity));
}
@media (min-width: 640px) {
.uno-qlmcrp {
text-align: left;
}
}Options
transformerCompileClass({
// Custom trigger string (default: ':uno:')
trigger: ':uno:',
// Custom class prefix (default: 'uno-')
classPrefix: 'uno-',
// Hash function for class names
hashFn: (str) => /* custom hash */,
// Keep original classes alongside compiled
keepOriginal: false,
})Use Cases
- Smaller HTML - Reduce repetitive class strings
- Obfuscation - Hide utility class names in production
- Performance - Fewer class attributes to parse
ESLint Integration
Enforce compile class usage across project:
{
"rules": {
"@unocss/enforce-class-compile": "warn"
}
}This rule:
- Warns when class attribute doesn't start with
:uno: - Auto-fixes by adding the prefix
Options:
{
"rules": {
"@unocss/enforce-class-compile": ["warn", {
"prefix": ":uno:",
"enableFix": true
}]
}
}Combining with Other Transformers
export default defineConfig({
transformers: [
transformerVariantGroup(), // Process variant groups first
transformerDirectives(), // Then directives
transformerCompileClass(), // Compile last
],
})<!-- Source references:
- https://unocss.dev/transformers/compile-class
-->
Transformer Directives
Enables @apply, @screen, theme(), and icon() directives in CSS.
Installation
import { defineConfig, transformerDirectives } from 'unocss'
export default defineConfig({
transformers: [
transformerDirectives(),
],
})@apply
Apply utility classes in CSS:
.custom-btn {
@apply py-2 px-4 font-semibold rounded-lg;
}
/* With variants - use quotes */
.custom-btn {
@apply 'hover:bg-blue-600 focus:ring-2';
}CSS Custom Property Alternative
For vanilla CSS compatibility:
.custom-div {
--at-apply: text-center my-0 font-medium;
}Supported aliases: --at-apply, --uno-apply, --uno
Configure aliases:
transformerDirectives({
applyVariable: ['--at-apply', '--uno-apply', '--uno'],
// or disable: applyVariable: false
})@screen
Create breakpoint media queries:
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
@screen sm {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
@screen lg {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}Breakpoint Variants
/* Less than breakpoint */
@screen lt-sm {
.item { display: none; }
}
/* At specific breakpoint only */
@screen at-md {
.item { width: 50%; }
}theme()
Access theme values in CSS:
.btn-blue {
background-color: theme('colors.blue.500');
padding: theme('spacing.4');
border-radius: theme('borderRadius.lg');
}Dot notation paths into your theme config.
icon()
Convert icon utility to SVG (requires preset-icons):
.icon-sun {
background-image: icon('i-carbon-sun');
}
/* With custom color */
.icon-moon {
background-image: icon('i-carbon-moon', '#fff');
}
/* Using theme color */
.icon-alert {
background-image: icon('i-carbon-warning', 'theme("colors.red.500")');
}Complete Example
.card {
@apply rounded-lg shadow-md p-4;
background-color: theme('colors.white');
}
.card-header {
@apply 'font-bold text-lg border-b';
padding-bottom: theme('spacing.2');
}
@screen md {
.card {
@apply flex gap-4;
}
}
.card-icon {
background-image: icon('i-carbon-document');
@apply w-6 h-6;
}<!-- Source references:
- https://unocss.dev/transformers/directives
-->
Transformer Variant Group
Enables shorthand syntax for grouping utilities with common prefixes.
Installation
import { defineConfig, transformerVariantGroup } from 'unocss'
export default defineConfig({
transformers: [
transformerVariantGroup(),
],
})Usage
Group multiple utilities under one variant prefix using parentheses:
<!-- Before transformation -->
<div class="hover:(bg-gray-400 font-medium) font-(light mono)" />
<!-- After transformation -->
<div class="hover:bg-gray-400 hover:font-medium font-light font-mono" />Examples
Hover States
<button class="hover:(bg-blue-600 text-white scale-105)">
Hover me
</button>Expands to: hover:bg-blue-600 hover:text-white hover:scale-105
Dark Mode
<div class="dark:(bg-gray-800 text-white)">
Dark content
</div>Expands to: dark:bg-gray-800 dark:text-white
Responsive
<div class="md:(flex items-center gap-4)">
Responsive flex
</div>Expands to: md:flex md:items-center md:gap-4
Nested Groups
<div class="lg:hover:(bg-blue-500 text-white)">
Large screen hover
</div>Expands to: lg:hover:bg-blue-500 lg:hover:text-white
Multiple Prefixes
<div class="text-(sm gray-600) font-(medium mono)">
Styled text
</div>Expands to: text-sm text-gray-600 font-medium font-mono
Key Points
- Use parentheses
()to group utilities - The prefix applies to all utilities inside the group
- Can be combined with any variant (hover, dark, responsive, etc.)
- Nesting is supported
- Works in class attributes and other extraction sources
<!-- Source references:
- https://unocss.dev/transformers/variant-group
-->
Related skills
Forks & variants (3)
Unocss has 3 known copies in the catalog totaling 635 installs. They canonicalize to this original listing.
- uni-helper - 539 installs
- hairyf - 89 installs
- jetbrains - 7 installs
How it compares
Use unocss when you need UnoCSS-specific preset and transformer setup rather than generic Tailwind migration guides.
FAQ
Where should UnoCSS configuration live?
unocss recommends a dedicated uno.config.ts file in the project root for best IDE support and HMR. The skill documents defineConfig imports and preset wiring inside that file.
Which UnoCSS presets does the unocss skill cover?
unocss documents presetWind3, presetAttributify, presetIcons, presetTypography, presetWebFonts, plus transformers transformerDirectives and transformerVariantGroup for a full utility-first setup.
Is Unocss safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.