How to Integrate UnoCSS with Astro: Complete Guide
Step-by-step guide to integrating UnoCSS with your Astro website.
UnoCSS is an atomic CSS engine that is instant and on-demand. It generates only the CSS you use, with zero parsing of your stylesheets. If you have used Tailwind CSS, UnoCSS will feel familiar, but it is fundamentally different under the hood. Instead of scanning your code for predefined utility classes, UnoCSS uses a rules engine that can match any pattern you define.
The result is faster builds, smaller CSS output, and extreme flexibility. You can use Tailwind-compatible syntax, Windi CSS syntax, or define completely custom utility patterns. For Astro sites, UnoCSS integrates directly into the build process through a Vite plugin.
Prerequisites
- Node.js 22.12.0 or higher (Astro 6 dropped Node 18 and Node 20 entirely, and the odd-numbered 19, 21, and 23 releases were never LTS)
- An Astro project (
npm create astro@latest)
Versions used in this guide, fetched from the npm registry and verified on 2026-05-29: astro 6.4.2, unocss 66.7.0, @unocss/astro 66.7.0, @unocss/reset 66.7.0. The unocss umbrella package re-exports every official preset and transformer, so you usually do not install the preset packages individually.
Installation
Install UnoCSS, the Astro integration, and the reset package:
npm install -D unocss@66.7.0 @unocss/astro@66.7.0 @unocss/reset@66.7.0
Configuration
Add UnoCSS to your astro.config.mjs. The official integration documents the import path as unocss/astro, and the integration does not inject a browser style reset by default, so opt in with injectReset: true:
import { defineConfig } from "astro/config";
import UnoCSS from "unocss/astro";
export default defineConfig({
integrations: [UnoCSS({ injectReset: true })],
});
Astro 6 renders to static HTML by default, so a CSS engine like UnoCSS that runs through a Vite plugin works with no adapter and no output setting. The output: 'hybrid' option was removed in Astro 5, and static and hybrid were merged into the default static mode. You only add an adapter when you opt a route into on-demand rendering with export const prerender = false. UnoCSS itself does not require any of that.
Create a uno.config.ts in your project root. UnoCSS renamed its default preset: presetUno (and the older presetWind) were deprecated in 66.0.0 and renamed to presetWind3, the Tailwind and Windi CSS compatible preset. Use presetWind3 instead of presetUno:
// uno.config.ts
import {
defineConfig,
presetWind3,
presetAttributify,
presetIcons,
presetTypography,
transformerDirectives,
transformerVariantGroup,
} from "unocss";
export default defineConfig({
presets: [
presetWind3(), // Tailwind/Windi CSS compatible utilities (successor to presetUno)
presetAttributify(), // Attributify mode (optional)
presetIcons({ scale: 1.2 }), // Icon support (optional)
presetTypography(), // Prose styles (optional)
],
transformers: [
transformerDirectives(), // @apply support
transformerVariantGroup(), // hover:(bg-red text-white)
],
theme: {
colors: {
primary: {
50: "#f0f9ff",
100: "#e0f2fe",
500: "#0ea5e9",
600: "#0284c7",
700: "#0369a1",
900: "#0c4a6e",
},
},
fontFamily: {
sans: ["Inter", "sans-serif"],
mono: ["JetBrains Mono", "monospace"],
},
},
shortcuts: {
btn: "px-4 py-2 rounded-lg font-medium transition-colors",
"btn-primary": "btn bg-primary-500 text-white hover:bg-primary-600",
"btn-outline":
"btn border border-gray-300 hover:border-primary-500 hover:text-primary-500",
container: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",
},
});
Import UnoCSS in your main layout:
---
// src/layouts/BaseLayout.astro
import "uno.css";
---
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<slot />
</body>
</html>
Basic Usage
Use utility classes just like Tailwind CSS:
---
// src/components/Card.astro
export interface Props {
title: string;
description: string;
}
const { title, description } = Astro.props;
---
<div class="bg-white rounded-xl shadow-md p-6 hover:shadow-lg transition-shadow">
<h3 class="text-xl font-bold text-gray-900 mb-2">{title}</h3>
<p class="text-gray-600 leading-relaxed">{description}</p>
<a href="#" class="btn-primary inline-block mt-4">Learn More</a>
</div>
Attributify Mode
The attributify preset lets you split classes into HTML attributes for cleaner markup:
<div
bg="white"
rounded="xl"
shadow="md hover:lg"
p="6"
transition="shadow"
>
<h3 text="xl gray-900" font="bold" mb="2">Title</h3>
<p text="gray-600" leading="relaxed">Description</p>
</div>
This produces the same CSS but keeps your HTML more readable when you have many utilities.
Variant Groups
The variant group transformer lets you group utilities under a shared variant:
<!-- Without variant groups -->
<div class="hover:bg-blue-500 hover:text-white hover:shadow-lg hover:scale-105">
Hover me
</div>
<!-- With variant groups -->
<div class="hover:(bg-blue-500 text-white shadow-lg scale-105)">
Hover me
</div>
Icons with UnoCSS
The icons preset lets you use any icon from Iconify directly as CSS classes. Install the Iconify JSON collections for the icon sets you want (versions verified on 2026-05-29: @iconify-json/heroicons 1.2.3, @iconify-json/lucide 1.2.111):
npm install -D @iconify-json/heroicons @iconify-json/lucide
<!-- Use icons as classes -->
<span class="i-heroicons-home w-6 h-6"></span>
<span class="i-lucide-search w-5 h-5 text-gray-400"></span>
<span class="i-heroicons-moon w-5 h-5 dark:i-heroicons-sun"></span>
No icon component libraries, no SVG imports. UnoCSS generates the icon as a CSS mask image.
Custom Rules
Define your own utility patterns:
// uno.config.ts
export default defineConfig({
rules: [
// Custom utility: text-balance
["text-balance", { "text-wrap": "balance" }],
// Custom utility: content-grid
[
"content-grid",
{
display: "grid",
"grid-template-columns":
"[full-start] 1fr [content-start] min(65ch, 100%) [content-end] 1fr [full-end]",
},
],
],
});
Use them like any other utility:
<div class="rounded-xl p-6">
<p class="text-balance">This text wraps more evenly across lines.</p>
</div>
Dark Mode
UnoCSS supports dark mode with the same dark: prefix:
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<h1 class="text-primary-600 dark:text-primary-400">
Works in both modes
</h1>
</div>
Production Tips
Use shortcuts for repeated patterns. Instead of writing
px-4 py-2 rounded-lg font-mediumon every button, define abtnshortcut in your config. This keeps your HTML clean and makes design changes easier.Check the generated CSS. Run
npx unocssto see what CSS UnoCSS generates. This helps you catch unused rules and verify that your custom patterns produce the correct output.Combine presets strategically. Start with
presetUno()for Tailwind compatibility. AddpresetIcons()only if you use CSS icons. AddpresetTypography()only if you need prose styles. Each preset adds to the processing time.Use safelist for dynamic classes. If you generate class names dynamically, add them to the safelist in your config so UnoCSS includes them in the output.
Migrate from Tailwind gradually. UnoCSS is compatible with most Tailwind utilities. You can switch your build from Tailwind to UnoCSS and most of your existing classes will work without changes.
Know the Wind3 to Wind4 path. presetWind3 is the direct, stable successor to the old presetUno and is what the official Astro example uses. presetWind4 is the newer Tailwind 4 compatible preset and is feature compatible with Wind3 with some adjusted theme keys. Start on presetWind3 for the smoothest migration off presetUno, then evaluate presetWind4 once your icon and typography presets confirm compatibility.
Alternatives to Consider
- Tailwind CSS if you prefer a larger ecosystem with more community plugins and official component libraries.
- Windi CSS (now deprecated) was the predecessor. Its ideas live on in UnoCSS.
- Open Props if you prefer CSS custom properties over utility classes.
Common Errors and Fixes
No styles at all after install. UnoCSS only generates CSS for the virtual
uno.cssmodule, so it does nothing until you import it. Addimport "uno.css";once in your root layout. This is separate from the reset.presetUno is not exportedor a deprecation warning on install.@unocss/preset-unoand@unocss/preset-windwere deprecated and renamed to@unocss/preset-wind3in 66.0.0. ReplacepresetUno()withpresetWind3()and import it fromunocss(or from@unocss/preset-wind3). The old import keeps working through the alias for now but logs a deprecation notice.Default browser margins and inconsistent box sizing. The Astro integration does not inject a style reset by default. Either pass
injectReset: true(or a path to a reset file) toUnoCSS()inastro.config.mjs, or import a reset manually such asimport "@unocss/reset/tailwind.css";in your layout.@applydoes nothing in a<style>block. Directives like@applyare handled bytransformerDirectives(), which is not enabled by default. Add it to thetransformersarray inuno.config.ts.Variant group syntax such as
hover:(...)is output literally. That grouping is provided bytransformerVariantGroup(). Add it totransformersor write the utilities out the long way.A dynamically constructed class name never renders. UnoCSS is on demand and only emits CSS for class strings it can statically see in your source. Class names assembled at runtime are invisible to the scanner, so list them in the
safelistarray in your config.An adapter or
outputsetting feels required. It is not for UnoCSS. Astro 6 is static by default,output: 'hybrid'was removed back in Astro 5, and you only add an adapter when a route opts into on-demand rendering withprerender = false. A pure UnoCSS styling setup needs none of that.
Official Docs and Examples
- UnoCSS Astro integration guide: https://unocss.dev/integrations/astro
- UnoCSS Wind3 preset (successor to
presetUno): https://unocss.dev/presets/wind3 - UnoCSS official presets index: https://unocss.dev/presets/
- Official UnoCSS Astro example repo: https://github.com/unocss/unocss/tree/main/examples/astro
- Astro v6 upgrade guide: https://docs.astro.build/en/guides/upgrade-to/v6/
- Astro on-demand rendering and adapters: https://docs.astro.build/en/guides/on-demand-rendering/
Wrapping Up
UnoCSS brings the utility-first approach to a new level of performance and flexibility. For Astro sites, the integration is seamless through the Vite plugin, build times are noticeably faster than Tailwind, and the generated CSS is as small as it gets. The custom rules engine means you are never limited to predefined utilities. If you want atomic CSS with room to grow, UnoCSS is the engine to build on.
Sources
Checked on 2026-05-29.
- UnoCSS Astro Integration. import path
unocss/astro, no default presets,injectResetand@unocss/reset - UnoCSS Wind3 preset.
presetUnoandpresetWinddeprecated and renamed topresetWind3 - UnoCSS Wind4 preset. Tailwind 4 compatible preset, feature compatible with Wind3
- UnoCSS official presets index. current
presetAttributify,presetIcons,presetTypography; deprecated preset-uno and preset-wind - Official UnoCSS Astro example repo.
astro.config.tsusesunocss/astrowithinjectReset: true;uno.config.tsusespresetWind3() - unocss on npm. version 66.7.0
- @unocss/astro on npm. version 66.7.0
- @unocss/reset on npm. version 66.7.0
- @iconify-json/heroicons on npm. version 1.2.3
- @iconify-json/lucide on npm. version 1.2.111
- astro on npm. version 6.4.2
- Upgrade to Astro v6. Node version requirements, static default
- Astro on-demand rendering. adapters only needed for on-demand routes
- Upgrade to Astro v5.
output: 'hybrid'removed, static and hybrid merged into static
Related Articles
How to Use Algolia with Astro: Complete Guide
Step-by-step guide to integrating Algolia with your Astro website.
How to Integrate Auth0 with Astro: Complete Guide
Step-by-step guide to integrating Auth0 with your Astro website. Setup, configuration, and best practices.
How to Use AWS Amplify with Astro: Complete Guide
Step-by-step guide to integrating AWS Amplify with your Astro website.