Nuxt UI
Vue component library built on Reka UI + Tailwind CSS + Tailwind Variants. Works with Nuxt, Vue (Vite), Laravel (Inertia), and AdonisJS (Inertia).
Installation
Nuxt
pnpm add @nuxt/ui tailwindcss
// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'] })
/* app/assets/css/main.css */ @import "tailwindcss"; @import "@nuxt/ui";
<!-- app.vue --> <template> <UApp> <NuxtPage /> </UApp> </template>
Vue (Vite)
pnpm add @nuxt/ui tailwindcss
// vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite'
export default defineConfig({ plugins: [ vue(), ui() ] })
// src/main.ts import './assets/main.css' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import ui from '@nuxt/ui/vue-plugin' import App from './App.vue'
const app = createApp(App)
const router = createRouter({ routes: [], history: createWebHistory() })
app.use(router) app.use(ui) app.mount('#app')
/* assets/main.css */ @import "tailwindcss"; @import "@nuxt/ui";
<!-- src/App.vue --> <template> <UApp> <RouterView /> </UApp> </template>
Vue: Add class="isolate" to your root <div id="app"> in index.html .
Vue + Inertia: Use ui({ router: 'inertia' }) in vite.config.ts .
UApp
Wrapping your app in UApp is required — it provides global config for toasts, tooltips, and programmatic overlays. It also accepts a locale prop for i18n (see composables reference).
Icons
Nuxt UI uses Iconify for 200,000+ icons. In Nuxt, @nuxt/icon is auto-registered. In Vue, icons work out of the box via the Vite plugin.
Naming convention
Icons use the format i-{collection}-{name} :
<UIcon name="i-lucide-sun" class="size-5" /> <UButton icon="i-lucide-plus" label="Add" /> <UAlert icon="i-lucide-info" title="Heads up" />
Browse all icons at icones.js.org. The lucide collection is used throughout Nuxt UI defaults.
Install icon collections locally
pnpm i @iconify-json/lucide pnpm i @iconify-json/simple-icons
Custom local collections (Nuxt)
// nuxt.config.ts export default defineNuxtConfig({ icon: { customCollections: [{ prefix: 'custom', dir: './app/assets/icons' }] } })
<UIcon name="i-custom-my-icon" />
Theming & Branding
Nuxt UI ships with a default look. The goal is to adapt it to your brand so every app looks unique.
Always use semantic utilities (text-default , bg-elevated , border-muted ), never raw Tailwind palette colors. See references/theming.md for the full list.
Colors
7 semantic colors (primary , secondary , success , info , warning , error , neutral ) configurable at runtime:
// Nuxt — app.config.ts export default defineAppConfig({ ui: { colors: { primary: 'indigo', neutral: 'zinc' } } })
// Vue — vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite'
export default defineConfig({ plugins: [ vue(), ui({ ui: { colors: { primary: 'indigo', neutral: 'zinc' } } }) ] })
Customizing components
Override priority (highest wins): ui prop / class prop > global config > theme defaults.
The ui prop overrides a component's slots after variants are computed — it wins over everything:
<UButton :ui="{ base: 'rounded-none', trailingIcon: 'size-3 rotate-90' }" /> <UCard :ui="{ header: 'bg-muted', body: 'p-8' }" />
Read the generated theme file to find slot names for any component:
-
Nuxt: .nuxt/ui/<component>.ts
-
Vue: node_modules/.nuxt-ui/ui/<component>.ts
For CSS variables, custom colors, global config, compound variants, and a full brand customization playbook, see references/theming.md
Composables
// Notifications const toast = useToast() toast.add({ title: 'Saved', color: 'success', icon: 'i-lucide-check' })
// Programmatic overlays const overlay = useOverlay() const modal = overlay.create(MyModal) const { result } = modal.open({ title: 'Confirm' }) await result
// Keyboard shortcuts defineShortcuts({ meta_k: () => openSearch(), escape: () => close() })
For full composable reference, see references/composables.md
Form validation
Uses Standard Schema — works with Zod, Valibot, Yup, or Joi.
<script setup lang="ts"> import { z } from 'zod'
const schema = z.object({ email: z.string().email('Invalid email'), password: z.string().min(8, 'Min 8 characters') })
type Schema = z.output<typeof schema> const state = reactive<Partial<Schema>>({ email: '', password: '' })
function onSubmit() { // UForm validates before emitting @submit — state is valid here } </script>
<template> <UForm :schema="schema" :state="state" @submit="onSubmit"> <UFormField name="email" label="Email" required> <UInput v-model="state.email" type="email" /> </UFormField>
<UFormField name="password" label="Password" required>
<UInput v-model="state.password" type="password" />
</UFormField>
<UButton type="submit">Sign in</UButton>
</UForm> </template>
For all form components and validation patterns, see references/components.md
Overlays
<!-- Modal --> <UModal v-model:open="isOpen" title="Edit" description="Edit your profile"> <template #body>Content</template> <template #footer> <UButton variant="ghost" @click="isOpen = false">Cancel</UButton> <UButton @click="save">Save</UButton> </template> </UModal>
<!-- Slideover (side panel) --> <USlideover v-model:open="isOpen" title="Settings" side="right"> <template #body>Content</template> </USlideover>
<!-- Dropdown menu (flat array) --> <UDropdownMenu :items="[ { label: 'Edit', icon: 'i-lucide-pencil' }, { type: 'separator' }, { label: 'Delete', icon: 'i-lucide-trash', color: 'error' } ]"> <UButton icon="i-lucide-ellipsis-vertical" variant="ghost" /> </UDropdownMenu>
<!-- Dropdown menu (nested array — groups with automatic separators) --> <UDropdownMenu :items="[ [{ label: 'Edit', icon: 'i-lucide-pencil' }, { label: 'Duplicate', icon: 'i-lucide-copy' }], [{ label: 'Delete', icon: 'i-lucide-trash', color: 'error' }] ]"> <UButton icon="i-lucide-ellipsis-vertical" variant="ghost" /> </UDropdownMenu>
For all overlay components, see references/components.md
Layouts
Nuxt UI provides components to compose full page layouts. Load the reference matching your use case:
Layout Description Reference
Page Landing, blog, changelog, pricing — public-facing pages layouts/page.md
Dashboard Admin UI with resizable sidebar and panels layouts/dashboard.md
Docs Documentation with sidebar nav and TOC layouts/docs.md
Chat AI chat with messages and prompt layouts/chat.md
Editor Rich text editor with toolbars layouts/editor.md
Templates
Official starter templates at github.com/nuxt-ui-templates:
Template Framework GitHub
Starter Nuxt nuxt-ui-templates/starter
Starter Vue nuxt-ui-templates/starter-vue
Dashboard Nuxt nuxt-ui-templates/dashboard
Dashboard Vue nuxt-ui-templates/dashboard-vue
SaaS Nuxt nuxt-ui-templates/saas
Landing Nuxt nuxt-ui-templates/landing
Docs Nuxt nuxt-ui-templates/docs
Portfolio Nuxt nuxt-ui-templates/portfolio
Chat Nuxt nuxt-ui-templates/chat
Editor Nuxt nuxt-ui-templates/editor
Changelog Nuxt nuxt-ui-templates/changelog
Starter Laravel nuxt-ui-templates/starter-laravel
Starter AdonisJS nuxt-ui-templates/starter-adonis
When starting a new project, clone the matching template instead of setting up from scratch.
Additional references
Load based on your task — do not load all at once:
-
references/theming.md — CSS variables, custom colors, component theme overrides
-
references/components.md — all 125+ components by category with props and usage
-
references/composables.md — useToast, useOverlay, defineShortcuts
-
Generated theme files — all slots, variants, and default classes for any component (Nuxt: .nuxt/ui/<component>.ts , Vue: node_modules/.nuxt-ui/ui/<component>.ts )