Tailwind CSS
Use and extend the maz-ui theme in your own Tailwind CSS v4 setup - theme colors, radius, shadows, spacing, breakpoints, custom utilities, dark mode, and how to add your own tokens, fonts, animations and variants.
This page is optional
maz-ui works without Tailwind: install the package, import maz-ui/style.css and the components render with the theme preset you chose.
This page is for apps that have their own Tailwind v4 setup and want their utilities (bg-primary, rounded-md, tab-m:flex...) to follow the active maz-ui theme, preset and color mode.
Setup
Add the maz-ui theme right after Tailwind in your Tailwind entry:
/* src/assets/css/main.css (your Tailwind entry) */
@import 'tailwindcss';
@import 'maz-ui/tailwindcss/theme.css';
@import 'maz-ui/tailwindcss/utilities.css';That's it: your utilities now resolve to the active maz-ui theme. Switch presets or color mode at runtime with useTheme() and every utility follows, without rebuild.
Prerequisites: tailwindcss@^4.2, @tailwindcss/vite or @tailwindcss/postcss (or @nuxtjs/tailwindcss v7 with Nuxt), and the theme initialized by the MazUi plugin or the @maz-ui/nuxt module.
Where to import maz-ui/style.css
maz-ui/style.css holds the styles of the components. It declares the same cascade layers as Tailwind (theme, base, components, utilities), so it composes with your own Tailwind output.
- Vue: keep
import 'maz-ui/style.css'inmain.ts, before your own CSS (see Vue guide). - Nuxt: the module injects it (
css.injectCss: true, the default). To control the CSS order yourself, disable the injection and import it first in your Tailwind entry:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@maz-ui/nuxt'],
css: ['~/assets/css/main.css'],
mazUi: {
css: { injectCss: false },
},
})/* app/assets/css/main.css */
@import 'maz-ui/style.css';
@import 'tailwindcss';
@import 'maz-ui/tailwindcss/theme.css';
@import 'maz-ui/tailwindcss/utilities.css';Never use the maz: prefix
The maz-ui library compiles its own utilities with an internal prefix(maz), and its documentation site does the same. That prefix never applies to your project: in your code, write bg-primary, flex, tab-m:grid, without maz:.
The utilities used inside the components ship precompiled in maz-ui/style.css, prefixed, so they never conflict with yours.
Granular entries
theme.css imports every module. Import only some of them if you want part of the design system:
| Import | Content |
|---|---|
maz-ui/tailwindcss/theme.css | Everything below except the utilities |
maz-ui/tailwindcss/theme-colors.css | Colors and their scales |
maz-ui/tailwindcss/theme-components.css | bg-container and bg-input surfaces |
maz-ui/tailwindcss/theme-spacing.css | Spacing scale |
maz-ui/tailwindcss/theme-radius.css | Border radius scale |
maz-ui/tailwindcss/theme-shadows.css | Shadow scale |
maz-ui/tailwindcss/theme-breakpoints.css | mob-*, tab-*, lap-* breakpoints |
maz-ui/tailwindcss/theme-z-index.css | z-index scale |
maz-ui/tailwindcss/theme-typography.css | Fonts, border width, durations and easings |
maz-ui/tailwindcss/theme-variants.css | dark: variant wired to the .dark class |
maz-ui/tailwindcss/utilities.css | maz-ui utilities (flex-center, padded-container...) |
Colors
Every theme color works with all the color utilities of Tailwind (bg-, text-, border-, ring-, outline-, fill-, stroke-, divide-, from-/via-/to-, decoration-, placeholder-, accent-, caret-...) and with opacity modifiers (bg-primary/50).
Brand and state colors
Each one has a paired -foreground color for text on top of it, and an 11-step scale from -50 (light) to -950 (dark), -500 being the base color.
| Color | Use for |
|---|---|
primary | Main actions, links, focus |
secondary | Secondary brand color |
accent | Highlights |
info | Informational state |
success | Success state |
warning | Warning state |
destructive | Errors, destructive actions |
contrast | Neutral high-contrast color (near black in light mode, near white in dark mode) |
<button class="bg-primary text-primary-foreground hover:bg-primary-600">Save</button>
<p class="rounded-md bg-success-50 p-3 text-success-800">Saved!</p>
<span class="bg-destructive/10 text-destructive">3 errors</span>Use maz-ui components first
For buttons, alerts and badges, use MazBtn, MazAlert and MazBadge: they already apply these colors. The utilities are for your own layouts and components.
Neutral and surface colors
They also have an 11-step scale, but no -foreground.
| Color | Use for |
|---|---|
surface | Page and container backgrounds |
foreground | Body text |
muted | Secondary text, placeholders, disabled content |
divider | Borders and separators |
overlay | Backdrops behind dialogs (bg-overlay/60) |
shadow | Shadow tint (shadow-shadow/20) |
<main class="bg-surface text-foreground">
<p class="text-muted">Last updated 3 days ago</p>
<hr class="border-divider">
</main>Component surfaces
Two colors follow the components block of the preset, to match the maz-ui components in your own ones:
bg-container: background ofMazCard,MazContainer,MazDialog,MazPopover,MazDrawer...bg-input: background ofMazInput,MazSelect,MazTextarea... (different from the surface in dark mode by default)
Light and dark modes
Theme colors are resolved with light-dark(): the same class gives the right color in both modes. Do not add dark: overrides for theme colors: bg-surface dark:bg-gray-900 is wrong, bg-surface is enough. Keep the dark: variant for real differences (an illustration, a different layout).
Avoid the default Tailwind palette
bg-blue-500, text-gray-600, bg-white, text-black or bg-[#1d90ff] ignore the preset and dark mode. Pick the theme color with the same role: bg-primary, text-muted, bg-surface, text-foreground. For a brand color missing from the theme, add your own token.
Radius
The rounded-* scale follows the scales.rounded of the preset:
| Utility | Value |
|---|---|
rounded-xs ... rounded-3xl | var(--maz-rounded-{xs..3xl}) |
rounded | same as rounded-md |
rounded-full and rounded-none keep their Tailwind values.
Shadows
| Utility | Use for |
|---|---|
shadow-xs, shadow-sm, shadow-md, shadow-lg, shadow-xl | Standard scale, from the preset scales.shadow |
shadow-elevation | Raised surfaces: cards, popovers, menus |
Spacing
--spacing is bound to the foundation.space token of the preset (0.25rem by default): p-4, gap-2, mt-6, w-10, inset-1... are multiples of it and rescale with the preset. Prefer the scale to arbitrary values such as p-[13px].
Breakpoints
maz-ui adds mobile-first breakpoints on top of the Tailwind ones (sm: to 2xl: keep working):
| Variant | Min width | Variant | Min width |
|---|---|---|---|
mob-s: | 320px | lap-s: | 1024px |
mob-m: | 425px | lap-m: | 1280px |
mob-l: | 576px | lap-l: | 1366px |
tab-s: | 640px | lap-xl: | 1440px |
tab-m: | 768px | lap-2xl: | 1680px |
tab-l: | 992px | lap-3xl: | 1920px |
Prefix them with max- for max-width queries: max-tab-m:hidden.
<div class="grid gap-4 tab-m:grid-cols-2 lap-m:grid-cols-3">...</div>The same values are available in TypeScript with import { screens } from 'maz-ui/tailwindcss' and the useBreakpoints composable.
Typography and motion
| Utility | Source |
|---|---|
font-sans | var(--maz-font-family) (preset foundation.font-family) |
font-mono | var(--maz-font-mono-stack) |
font-display | var(--maz-font-display-stack) (headings) |
ease-out, ease-in, ease-in-out | var(--maz-easing-*) |
duration-(--duration-fast), duration-(--duration-normal), duration-(--duration-slow) | var(--maz-motion-*) |
The default border width and the default transition duration and easing follow the preset too. Durations are theme variables, not named utilities: write transition-colors duration-(--duration-fast).
z-index
z-1 to z-5, z-15, z-25, z-35, z-45, z-75, z-100, and z-default-backdrop (1050, the layer of MazDialog and the toasts).
maz-ui utilities
maz-ui/tailwindcss/utilities.css adds:
| Utility | Effect |
|---|---|
flex-center | align-items: center; justify-content: center (combine with flex) |
padded-container | Full width with responsive horizontal padding, content centered within --maz-container-max-width |
padded-container-no-p | Same centering without the minimum padding |
cap-f | Capitalizes the first letter |
disabled-state, disabled-opacity, disabled-cursor | The disabled look of the preset |
z-default-backdrop | z-index: 1050 |
<section class="padded-container py-12">
<div class="flex flex-center gap-2">...</div>
</section>Container width
padded-container reads CSS variables that you can override:
| Variable | Default |
|---|---|
--maz-container-max-width | 1440px |
--maz-container-padding-mobile | 1rem |
--maz-container-padding-tablet | 2rem (from mob-l) |
--maz-container-padding-desktop | 2.5rem (from lap-s) |
The content stops growing at --maz-container-max-width once the viewport is wider than the max width plus twice the desktop padding. When you change the max width, update that threshold too:
@layer base {
html {
--maz-container-max-width: 1024px;
}
/* 1024px + 2 * 2.5rem */
@media (width >= 1104px) {
:root {
--maz-container-width: var(--maz-container-max-width);
}
}
}Vue transitions
maz-ui/style.css ships transition classes you can reuse with <Transition name="...">: maz-scale-fade, maz-scale, maz-slide, maz-slideinvert, maz-slidevnext, maz-slidevprev, maz-expand.
Dark mode variant
maz-ui/tailwindcss/theme-variants.css binds dark: to the .dark class that useTheme() sets on <html> (darkModeStrategy: 'class', the default). Adapt it when you change the strategy:
/* darkModeStrategy: 'media' */
@custom-variant dark (@media (prefers-color-scheme: dark));
/* custom darkClass: 'theme-dark' */
@custom-variant dark (&:where(.theme-dark, .theme-dark *));Toggle the mode with useTheme() (toggleDarkMode(), setColorMode('dark' | 'light' | 'auto')), never by editing the class yourself: see Theming.
Extending the theme
How the layers fit together
Your theme is built from three layers, from the most global to the most specific:
- The preset (
definePresetof@maz-ui/themes) gives the values: it emits runtime CSS variables (--maz-primary,--maz-font-family,--maz-rounded-md,--maz-motion-fast...) for the light and dark modes. - The maz-ui theme (
maz-ui/tailwindcss/theme.css) gives the class names: it maps each Tailwind token to a preset variable (--color-primary: var(--maz-primary),--font-display: var(--maz-font-display-stack)).bg-primaryorfont-displaytherefore follow the active preset and color mode, without rebuild. - Your Tailwind entry gives the project tokens: everything you declare after the maz-ui imports (
@theme,@custom-variant,@utility) adds classes next to the maz-ui ones.
| You want | Put it in | You get |
|---|---|---|
| Brand colors, fonts, radius, shadows, motion, spacing | the preset (colors, foundation, scales) | the same maz-ui classes with your values, components included |
| Background of cards and inputs, button font weight | the preset (components) | bg-container, bg-input, MazBtn |
| A color outside the maz-ui roles (chart series, category) | @theme { --color-* } | bg-<name>, text-<name>... |
| An animation | @theme { --animate-* } + @keyframes | animate-<name> |
| A variant (short screens, a state) | @custom-variant | <name>: |
| A reusable group of declarations | @utility | <name> |
The width of padded-container | --maz-container-max-width in your base layer | Container width |
Redefining a maz-ui token
A token you redefine in your @theme (--color-primary, --font-sans, --radius-md...) replaces the maz-ui mapping: the class keeps your literal value and stops following the preset (preset switch, light and dark values). Change brand values in the preset instead; redefine a token only when you need it, for example to give a literal font name to @nuxt/fonts (see Fonts).
Brand colors: use a preset
Your brand colors, radius, fonts and spacing belong to a theme preset: every maz-ui component and every Tailwind utility (bg-primary, rounded-md, font-sans...) then use them, in light and dark modes.
import { definePreset } from '@maz-ui/themes'
import { mazUi } from '@maz-ui/themes/presets/mazUi'
export const brandPreset = definePreset({
base: mazUi,
overrides: {
name: 'brand',
foundation: {
'font-family': 'Archivo, ui-sans-serif, system-ui, sans-serif',
},
scales: {
rounded: { md: '0.5rem' },
},
colors: {
light: { primary: 'oklch(0.62 0.2 255)' },
dark: { primary: 'oklch(0.72 0.17 255)' },
},
},
})See Creating custom themes and the Theme Editor.
Add your own colors
For a color outside the maz-ui roles (a chart series, a product category), declare it once in your Tailwind entry. light-dark() works because maz-ui sets color-scheme:
@theme {
--color-brand: light-dark(oklch(0.65 0.21 30), oklch(0.75 0.17 30));
}bg-brand, text-brand/80 and border-brand are now available. To base a color on a maz-ui token, use @theme inline so the utility reads the variable at runtime:
@theme inline {
--color-primary-soft: color-mix(in oklab, var(--maz-primary) 15%, transparent);
}Fonts
The font utilities read the preset: font-sans uses foundation.font-family, font-display uses font-display-stack and font-mono uses font-mono-stack. You can also redefine them in your Tailwind entry, after the maz-ui import (keep the same stacks as the preset, the classes no longer follow it):
@theme {
--font-sans: Archivo, ui-sans-serif, system-ui, sans-serif;
--font-display: 'Barlow Condensed', 'Arial Narrow', sans-serif;
}Nuxt fonts
With @nuxt/fonts, write the font family name literally (not only var(--maz-font-family)) somewhere in your CSS so the module detects it and self-hosts it.
Animations
Declare --animate-* tokens and their keyframes, reusing the motion tokens of the theme:
@theme {
--animate-rise: rise 0.5s var(--maz-easing-out) backwards;
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(1rem);
}
}<h1 class="animate-rise">Welcome</h1>Variants
Add your own variants next to the maz-ui ones:
/* short screens (small Android, landscape) */
@custom-variant short (@media (max-height: 50rem));<header class="py-8 short:py-3">...</header>Base styles
A typical base layer that applies the theme to the document:
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--maz-divider);
}
html {
font-family: var(--maz-font-family);
font-size: var(--maz-base-font-size);
color: var(--maz-foreground);
background-color: var(--maz-surface);
}
::selection {
background-color: color-mix(in srgb, var(--maz-primary) 28%, transparent);
}
}Complete example
/* app/assets/css/main.css */
@import 'maz-ui/style.css';
@import 'tailwindcss';
@import 'maz-ui/tailwindcss/theme.css';
@import 'maz-ui/tailwindcss/utilities.css';
@custom-variant short (@media (max-height: 50rem));
@theme {
--font-display: 'Barlow Condensed', 'Arial Narrow', sans-serif;
--color-brand: light-dark(oklch(0.65 0.21 30), oklch(0.75 0.17 30));
--animate-rise: rise 0.5s var(--maz-easing-out) backwards;
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(1rem);
}
}
@layer base {
html {
--maz-container-max-width: 1200px;
font-family: var(--maz-font-family);
color: var(--maz-foreground);
background-color: var(--maz-surface);
}
}Custom CSS
In plain CSS or in <style> blocks, use the theme variables rather than literal values:
.card {
padding: calc(var(--maz-space) * 4);
border: var(--maz-border-width) solid var(--maz-divider);
border-radius: var(--maz-rounded-md);
background-color: var(--maz-container-bg, var(--maz-surface));
box-shadow: var(--maz-shadow-style-elevation);
color: var(--maz-foreground);
transition: background-color var(--maz-motion-fast) var(--maz-easing-out);
}The full list of variables is in the token reference of the theming guide.
@apply in Vue SFC <style> blocks
Tailwind v4 processes each SFC <style> block in isolation: a block that uses @apply must start with a @reference to your Tailwind entry.
<style scoped>
@reference "../assets/css/main.css";
.card {
@apply flex gap-4 rounded-md bg-surface p-4 shadow-elevation;
}
</style>AI agents
Every class and variable of this page is available to AI coding agents, generated from the sources of the installed version: the get_theme_tokens tool of the maz-ui MCP server, and node_modules/maz-ui/agent-docs/reference/tailwind-tokens.md. See AI agents.
get_theme_tokens also reads your theme: the Tailwind entries of the project (CSS files with @theme, @custom-variant, @utility or a tailwindcss import) and the definePreset calls, in every app of a monorepo. Agents get your preset values, your tokens with their comments (animate-rise, font-display, short:...), the tokens that redefine a maz-ui one and the setup problems (missing maz-ui import). A comment above a token in your @theme is a good place to say when to use it.
Migrating from Tailwind v3
Run the official upgrade tool first, it handles most of the v3 to v4 transition (renamed utilities, tailwind.config.js to CSS-first configuration):
npx @tailwindcss/upgradeThen apply the maz-ui specific changes of the v4 to v5 migration guide.
See also
- Theming: presets, color modes, runtime switching
- Migration v4 to v5
- Browser support: minimum versions required by Tailwind v4