# Installation \> \[!NOTE] \> See: /docs/getting-started/installation/vue \> Looking for the Vue version? ## Setup ### Add to a Nuxt project Install the Nuxt UI package \`\`\`bash pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun add @nuxt/ui tailwindcss \`\`\` Add the Nuxt UI module in your nuxt.config.ts \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'] }) \`\`\` Import Tailwind CSS and Nuxt UI in your CSS \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'], css: \['\~/assets/css/main.css'] }) \`\`\` \> \[!TIP] \> See: https\://nuxt.com/docs/getting-started/layers \> When using \[Nuxt Layers]\(https\://nuxt.com/docs/getting-started/layers), the module automatically generates \[\`@source\`]\(https\://tailwindcss.com/docs/functions-and-directives#source-directive) directives for each layer directory, ensuring Tailwind CSS scans all your layer source files for utility classes. \> \[!NOTE] \> It's recommended to install the \[Tailwind CSS IntelliSense]\(https\://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings: \> \`\`\`json \> { \> "files.associations": { \> "\*.css": "tailwindcss" \> }, \> "editor.quickSuggestions": { \> "strings": "on" \> }, \> "tailwindCSS.classAttributes": \["class", "ui"], \> "tailwindCSS.experimental.classRegex": \[ \> \["\['\\"\`]\(\[^'\\"\`]\*)\['\\"\`]"] \> ] \> } \> \> \`\`\` Wrap your app with App component \`\`\`vue \ \`\`\` \> \[!NOTE] \> See: /docs/components/app \> The \`App\` component provides global configurations and is required for Toast, Tooltip components to work as well as Programmatic Overlays. ### Use a Nuxt template Get started with one of our [official templates](https://ui.nuxt.com/templates) by using the `Use this template` button on GitHub or the CLI: \`\`\`bash npm create nuxt\@latest -- -t ui \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/landing \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/docs \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/saas \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/dashboard \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/chat \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/portfolio \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/changelog \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/editor \`\`\` \*\*Starter\*\* A minimal template to get started with Nuxt UI. \*\*Landing\*\* A modern landing page template powered by Nuxt Content. \*\*Docs\*\* A documentation template powered by Nuxt Content. \*\*SaaS\*\* A SaaS template with landing, pricing, docs and blog powered by Nuxt Content. \*\*Dashboard\*\* A dashboard template with multi-column layout for building sophisticated admin interfaces. \*\*Chat\*\* An AI chatbot template to build your own chatbot powered by Vercel AI SDK. \*\*Portfolio\*\* A sleek portfolio template to showcase your work, skills and blog powered by Nuxt Content. \*\*Changelog\*\* A changelog template to display your repository releases notes from GitHub powered by Nuxt MDC. \*\*Editor\*\* A rich text editor template powered by TipTap with support for markdown, HTML, and JSON content types. ## Options You can customize Nuxt UI by providing options in your `nuxt.config.ts`. ### `prefix` Use the `prefix` option to change the prefix of the components. - Default: `U`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { prefix: 'Nuxt' } }) ``` ### `fonts` Use the `fonts` option to enable or disable the [`@nuxt/fonts`](https://github.com/nuxt/fonts){rel=""nofollow""} module. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { fonts: false } }) ``` ### `colorMode` Use the `colorMode` option to enable or disable the [`@nuxt/color-mode`](https://github.com/nuxt-modules/color-mode){rel=""nofollow""} module. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { colorMode: false } }) ``` ### `theme.colors` Use the `theme.colors` option to define the dynamic color aliases used to generate components theme. - Default: `['primary', 'secondary', 'success', 'info', 'warning', 'error']`{.inline,language-ts-type,shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { colors: ['primary', 'error'] } } }) ``` \> \[!TIP] \> See: /docs/getting-started/theme/design-system#colors \> Learn more about color customization and theming in the Theme section. ### `theme.transitions` Use the `theme.transitions` option to enable or disable transitions on components. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { transitions: false } } }) ``` \> \[!NOTE] \> This option adds the \`transition-colors\` class on components with hover or active states. ### `theme.defaultVariants` Use the `theme.defaultVariants` option to override the default `color` and `size` variants for components. - Default: `{ color: 'primary', size: 'md' }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-11} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { defaultVariants: { color: 'neutral', size: 'sm' } } } }) ``` ### `theme.prefix` `4.2+` Use the `theme.prefix` option to configure the same prefix you set on your Tailwind CSS import. This ensures Nuxt UI components use the correct prefixed utility classes and CSS variables. \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'], css: \['\~/assets/css/main.css'], ui: { theme: { prefix: 'tw' } } }) \`\`\` \`\`\`css @import "tailwindcss" prefix(tw); @import "@nuxt/ui"; \`\`\` \> \[!WARNING] \> See: https\://fonts.nuxt.com/get-started/configuration#processcssvariables \> You might need to enable \`fonts.processCSSVariables\` to use the prefix option with the \`@nuxt/fonts\` module: \> \`\`\`ts \> export default defineNuxtConfig({ \> modules: \['@nuxt/ui'], \> css: \['\~/assets/css/main.css'], \> ui: { \> theme: { \> prefix: 'tw' \> } \> }, \> fonts: { \> processCSSVariables: true \> } \> }) \> \> \`\`\` This will automatically prefix all Tailwind utility classes and CSS variables in Nuxt UI component themes: ```html ``` \> \[!NOTE] \> See: https\://tailwindcss.com/docs/styling-with-utility-classes#using-the-prefix-option \> Learn more about using a prefix in the Tailwind CSS documentation. ### `prose` Use the `prose` option to force the import of Nuxt UI `` components even if `@nuxtjs/mdc` or `@nuxt/content` is not installed. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { prose: true } }) ``` ### `mdc` `Deprecated` Use the [`prose`](https://ui.nuxt.com/#prose) option instead. ### `content` Use the `content` option to force the import of Nuxt UI `` and `` components even if `@nuxt/content` is not installed. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { content: true } }) ``` ### `experimental.componentDetection` `4.1+` Use the `experimental.componentDetection` option to enable automatic component detection for tree-shaking. This feature scans your source code to detect which components are actually used and only generates the necessary CSS for those components (including their dependencies). - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - Type: `boolean | string[]`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} **Enable automatic detection:** ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { experimental: { componentDetection: true } } }) ``` **Include additional components for dynamic usage:** ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { experimental: { componentDetection: ['Modal', 'Dropdown', 'Popover'] } } }) ``` \> \[!NOTE] \> When providing an array of component names, automatic detection is enabled and these components (along with their dependencies) are guaranteed to be included. This is useful for dynamic components like \`\\` that can't be statically analyzed. ## Continuous releases Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new){rel=""nofollow""} for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Automatic preview releases are created for all commits and PRs to the `v4` branch. Use them by replacing your package version with the specific commit hash or PR number. ```diff [package.json] { "dependencies": { - "@nuxt/ui": "^4.0.0", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909", } } ``` \> \[!NOTE] \> pkg.pr.new will automatically comment on PRs with the installation URL, making it easy to test changes. # Installation \> \[!NOTE] \> See: /docs/getting-started/installation/nuxt \> Looking for the Nuxt version? ## Setup ### Add to a Vue project Install the Nuxt UI package \`\`\`bash pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun add @nuxt/ui tailwindcss \`\`\` Add the Nuxt UI Vite plugin in your vite.config.ts \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), ui() ] }) \`\`\` \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' import laravel from 'laravel-vite-plugin' export default defineConfig({ plugins: \[ laravel({ input: \['resources/js/app.ts'], refresh: true }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false } } }), ui({ router: 'inertia' }) ] }) \`\`\` \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' import adonisjs from '@adonisjs/vite/client' import inertia from '@adonisjs/inertia/client' export default defineConfig({ plugins: \[ adonisjs({ entrypoints: \['inertia/app/app.ts'], reload: \['resources/views/\*\*/\*.edge'] }), inertia(), vue(), ui({ router: 'inertia' }) ] }) \`\`\` \> \[!TIP] \> Nuxt UI registers \`unplugin-auto-import\` and \`unplugin-vue-components\`, which will generate \`auto-imports.d.ts\` and \`components.d.ts\` type declaration files. You will likely want to gitignore these, and add them to your \`tsconfig\`. \> \`\`\`json \> { \> "include": \["src/\*\*/\*.ts", "src/\*\*/\*.tsx", "src/\*\*/\*.vue", "auto-imports.d.ts", "components.d.ts"] \> } \> \> \`\`\` \> \> \`\`\`bash \> # Auto-generated type declarations \> auto-imports.d.ts \> components.d.ts \> \> \`\`\` \> \[!TIP] \> Internally, Nuxt UI relies on custom alias to resolve the theme types. If you're using TypeScript, you should add an alias to your \`tsconfig\` to enable auto-completion in your \`vite.config.ts\`. \> \`\`\`json \> { \> "compilerOptions": { \> "paths": { \> "#build/ui": \[ \> "./node\_modules/.nuxt-ui/ui" \> ] \> } \> } \> } \> \> \`\`\` \> \> \`\`\`json \> { \> "compilerOptions": { \> "paths": { \> "#build/ui/\*": \[ \> "./node\_modules/.nuxt-ui/ui/\*" \> ] \> } \> } \> } \> \> \`\`\` Use the Nuxt UI Vue plugin \`\`\`ts 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') \`\`\` \`\`\`ts import type { DefineComponent } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import ui from '@nuxt/ui/vue-plugin' import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers' import { createApp, h } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'Laravel x Nuxt UI' createInertiaApp({ title: title => (title ? \`${title} - ${appName}\` : appName), resolve: name => resolvePageComponent( \`./pages/${name}.vue\`, import.meta.glob\('./pages/\*\*/\*.vue') ), setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .use(ui) .mount(el) } }) \`\`\` \`\`\`ts import type { DefineComponent } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import ui from '@nuxt/ui/vue-plugin' import { resolvePageComponent } from '@adonisjs/inertia/helpers' import { createApp, h } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'AdonisJS x Nuxt UI' createInertiaApp({ title: title => (title ? \`${title} - ${appName}\` : appName), resolve: name => resolvePageComponent( \`../pages/${name}.vue\`, import.meta.glob\('../pages/\*\*/\*.vue') ), setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .use(ui) .mount(el) } }) \`\`\` Import Tailwind CSS and Nuxt UI in your CSS \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \> \[!TIP] \> Import the CSS file in your entrypoint. \> \`\`\`ts \> import './assets/css/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') \> \> \`\`\` \> \> \`\`\`ts \> import '../css/app.css' \> import type { DefineComponent } from 'vue' \> import { createInertiaApp } from '@inertiajs/vue3' \> import ui from '@nuxt/ui/vue-plugin' \> import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers' \> import { createApp, h } from 'vue' \> \> const appName = import.meta.env.VITE\_APP\_NAME || 'Laravel x Nuxt UI' \> \> createInertiaApp({ \> title: title => (title ? \`${title} - ${appName}\` : appName), \> resolve: name => \> resolvePageComponent( \> \`./pages/${name}.vue\`, \> import.meta.glob\('./pages/\*\*/\*.vue') \> ), \> setup({ el, App, props, plugin }) { \> createApp({ render: () => h(App, props) }) \> .use(plugin) \> .use(ui) \> .mount(el) \> } \> }) \> \> \`\`\` \> \> \`\`\`ts \> import '../css/app.css' \> import type { DefineComponent } from 'vue' \> import { createInertiaApp } from '@inertiajs/vue3' \> import ui from '@nuxt/ui/vue-plugin' \> import { resolvePageComponent } from '@adonisjs/inertia/helpers' \> import { createApp, h } from 'vue' \> \> const appName = import.meta.env.VITE\_APP\_NAME || 'AdonisJS x Nuxt UI' \> \> createInertiaApp({ \> title: title => (title ? \`${title} - ${appName}\` : appName), \> resolve: name => \> resolvePageComponent( \> \`../pages/${name}.vue\`, \> import.meta.glob\('../pages/\*\*/\*.vue') \> ), \> setup({ el, App, props, plugin }) { \> createApp({ render: () => h(App, props) }) \> .use(plugin) \> .use(ui) \> .mount(el) \> } \> }) \> \> \`\`\` \> \[!NOTE] \> It's recommended to install the \[Tailwind CSS IntelliSense]\(https\://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings: \> \`\`\`json \> { \> "files.associations": { \> "\*.css": "tailwindcss" \> }, \> "editor.quickSuggestions": { \> "strings": "on" \> }, \> "tailwindCSS.classAttributes": \["class", "ui"], \> "tailwindCSS.experimental.classRegex": \[ \> \["\['\\"\`]\(\[^'\\"\`]\*)\['\\"\`]"] \> ] \> } \> \> \`\`\` Wrap your app with App component \`\`\`vue \ \`\`\` \`\`\`vue \ \`\`\` \`\`\`vue \ \`\`\` \> \[!NOTE] \> See: /docs/components/app \> The \`App\` component sets up global config and is required for Toast, Tooltip and programmatic overlays. Add the isolate class to your root container \`\`\`html \ \ \ \ \ \Nuxt UI\ \ \ \
\
\ \ \ \`\`\` \`\`\`blade \ \ \ \ \ @inertiaHead @vite('resources/js/app.ts') \ \ \
@inertia \
\ \ \`\`\` \`\`\`edge \ \ \ \ \ @inertiaHead() @vite(\['inertia/app/app.ts', \`inertia/pages/${page.component}.vue\`]) \ \ @inertia({ class: 'isolate' }) \ \ \`\`\` \> \[!NOTE] \> This ensures styles are scoped to your app and prevents issues with overlays and stacking contexts. ### Use a Vue template Get started with one of our [official templates](https://ui.nuxt.com/templates) by using the `Use this template` button on GitHub or the CLI: \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue \`\`\` \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue/dashboard \`\`\` \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue/chat \`\`\` \*\*Starter\*\* A minimal template to get started with Nuxt UI. \*\*Dashboard\*\* A dashboard template with multi-column layout for building sophisticated admin interfaces. \*\*Chat\*\* An AI chatbot template to build your own chatbot powered by Vercel AI SDK. \*\*Starter Adonis\*\* A minimal Nuxt UI template for AdonisJS using Inertia.js. \*\*Starter Laravel\*\* A minimal Nuxt UI template for Laravel using Inertia.js. ## Options You can customize Nuxt UI by providing options in your `vite.config.ts`. ### `prefix` Use the `prefix` option to change the prefix of the components. - Default: `U`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ prefix: 'Nuxt' }) ] }) ``` ### `ui` Use the `ui` option to provide configuration for Nuxt UI. ```ts [vite.config.ts] {9-14} 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: 'green', neutral: 'slate' } } }) ] }) ``` ### `colorMode` Use the `colorMode` option to enable or disable the color mode integration from `@vueuse/core`. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ colorMode: false }) ] }) ``` ### `theme.colors` Use the `theme.colors` option to define the dynamic color aliases used to generate components theme. - Default: `['primary', 'secondary', 'success', 'info', 'warning', 'error']`{.inline,language-ts-type,shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-11} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { colors: ['primary', 'error'] } }) ] }) ``` \> \[!TIP] \> See: /docs/getting-started/theme/design-system#colors \> Learn more about color customization and theming in the Theme section. ### `theme.transitions` Use the `theme.transitions` option to enable or disable transitions on components. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-11} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { transitions: false } }) ] }) ``` \> \[!NOTE] \> This option adds the \`transition-colors\` class on components with hover or active states. ### `theme.defaultVariants` Use the `theme.defaultVariants` option to override the default `color` and `size` variants for components. - Default: `{ color: 'primary', size: 'md' }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-14} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { defaultVariants: { color: 'neutral', size: 'sm' } } }) ] }) ``` ### `theme.prefix` `4.2+` Use the `theme.prefix` option to configure the same prefix you set on your Tailwind CSS import. This ensures Nuxt UI components use the correct prefixed utility classes and CSS variables. \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), ui({ theme: { prefix: 'tw' } }) ] }) \`\`\` \`\`\`css @import "tailwindcss" prefix(tw); @import "@nuxt/ui"; \`\`\` This will automatically prefix all Tailwind utility classes and CSS variables in Nuxt UI component themes: ```html ``` \> \[!NOTE] \> See: https\://tailwindcss.com/docs/styling-with-utility-classes#using-the-prefix-option \> Learn more about using a prefix in the Tailwind CSS documentation. ### `prose` Use the `prose` option to enable Nuxt UI `` components and their theme. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ prose: true }) ] }) ``` ### `autoImport` Use the `autoImport` option to disable composable auto-imports or to customize [`unplugin-auto-import`](https://github.com/unplugin/unplugin-auto-import){rel=""nofollow""} options. - Default: `{}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ autoImport: false }) ] }) ``` \> \[!NOTE] \> When disabled, you can still import composables explicitly from \`@nuxt/ui/composables\`. ### `components` Use the `components` option to disable component auto-imports or to customize [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components){rel=""nofollow""} options. - Default: `{}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ components: false }) ] }) ``` \> \[!NOTE] \> When disabled, you can still import components explicitly, e.g. \`import Button from '@nuxt/ui/components/Button.vue'\` or \`import ProseCode from '@nuxt/ui/components/prose/Code.vue'\`. ### `router` `4.3+` Use the `router` option to configure routing integration. This is useful for applications that don't use `vue-router`, such as Electron apps, MPAs, or frameworks like [Inertia.js](https://inertiajs.com/){rel=""nofollow""} or [Hybridly](https://hybridly.dev/){rel=""nofollow""}. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} | Value | Description | | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | `true`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Uses `vue-router` for navigation with `RouterLink` component. | | `false`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Disables routing integration, links render as plain `` tags. | | `'inertia'`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Uses Inertia.js for navigation with its `Link` component. | ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ router: false }) ] }) ``` \> \[!TIP] \> You can provide custom navigation logic for frameworks like Hybridly by setting \`router: false\` in the Vite config and passing a function when installing the Vue plugin: \> \`\`\`ts \> import ui from '@nuxt/ui/vue-plugin' \> import { router } from 'hybridly' \> \> app.use(ui, { \> router: (event, { href, external }) => { \> if (external) { \> return \> } \> \> event.preventDefault() \> \> router.navigate({ url: href }) \> } \> }) \> \> \`\`\` \> \[!NOTE] \> When set to \`false\` or \`'inertia'\`, \`vue-router\` is not required as a dependency. ### `scanPackages` `4.3+` Use the `scanPackages` option to specify additional npm packages that should be scanned for components using Nuxt UI. This is useful when you have a shared component library that uses Nuxt UI components internally. ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ scanPackages: ['@my-org/ui-components'] }) ] }) ``` \> \[!NOTE] \> By default, only \`@nuxt/ui\` is scanned. Use this option when your external packages contain Vue components that use Nuxt UI. ## Continuous releases Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new){rel=""nofollow""} for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Automatic preview releases are created for all commits and PRs to the `v4` branch. Use them by replacing your package version with the specific commit hash or PR number. ```diff [package.json] { "dependencies": { - "@nuxt/ui": "^4.0.0", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909", } } ``` \> \[!NOTE] \> pkg.pr.new will automatically comment on PRs with the installation URL, making it easy to test changes. # Introduction ## What is Nuxt UI? A modern Vue UI component library built on [Reka UI](https://reka-ui.com/){rel=""nofollow""}, [Tailwind CSS](https://tailwindcss.com/){rel=""nofollow""}, and [Tailwind Variants](https://www.tailwind-variants.org/){rel=""nofollow""} to ship beautiful and accessible applications with 125+ production-ready components. Works with Nuxt and plain Vue apps (Vite, Inertia, SSR). If you're building a Vue project with Tailwind CSS, Nuxt UI is a great default choice. It provides high-level, ready-to-use components (data tables, forms, overlays, navigation) while still allowing advanced customization when needed. \*\*Developer Experience First\*\* Intuitive APIs, excellent TypeScript support, auto-completion, and comprehensive docs. \*\*Beautiful by Default\*\* A modern, clean design out of the box with a theme you can adapt in minutes. \*\*Accessible by Default\*\* WAI-ARIA compliant with keyboard navigation, focus management, and screen reader support. \*\*Production Ready\*\* 125+ battle-tested components including data tables, forms, overlays, and navigation used by thousands of applications in production. ## What's new in v4? Nuxt UI v4 marks a major milestone: Nuxt UI and Nuxt UI Pro are now unified into a single, fully open-source and free library of 125+ production-ready components and a complete Figma Kit. The migration from v3 to v4 will be much smoother than from v2 to v3. Read more in the [migration guide](https://ui.nuxt.com/docs/getting-started/migration/v4). \> \[!NOTE] \> See: /docs/getting-started/migration/v3 \> If you are migrating from v2, you can read more in this migration guide. ## Core technologies ### Reka UI Nuxt UI is built on top of [Reka UI](https://reka-ui.com/){rel=""nofollow""} as a foundation for the components: - **WAI-ARIA Compliance**: Follows [WAI-ARIA authoring practices](https://reka-ui.com/docs/overview/accessibility){rel=""nofollow""} with proper semantics and roles - **Keyboard Navigation**: Built-in keyboard support for complex components like tabs and dialogs - **Focus Management**: Intelligent focus handling that moves focus based on user interactions - **Accessible Labels**: Abstractions to simplify labeling controls for screen readers ### Tailwind CSS Nuxt UI integrates the latest [Tailwind CSS](https://tailwindcss.com/){rel=""nofollow""}, bringing significant improvements: - **5x Faster Builds**: Full builds up to 5x faster, incremental builds over 100x faster - **Unified Toolchain**: Built-in import handling, vendor prefixing, and syntax transforms - **CSS-first Configuration**: Customize and extend directly in CSS instead of JavaScript - **Modern Web Features**: Container queries, cascade layers, wide-gamut colors, and more ### Tailwind Variants Nuxt UI takes advantage of [Tailwind Variants](https://www.tailwind-variants.org/){rel=""nofollow""} to provide a powerful design system: - **Dynamic Styling**: Flexible component variants with a powerful API - **Type Safety**: Full TypeScript support with auto-completion - **Conflict Resolution**: Efficient merging of conflicting styles ## Key features ### Ecosystem integration Nuxt UI is SSR compatible and integrates seamlessly with the Nuxt ecosystem (these features also work in Vue with additional configuration): - [**Icons**](https://ui.nuxt.com/docs/getting-started/integrations/icons): Access 200,000+ icons from Iconify - [**Fonts**](https://ui.nuxt.com/docs/getting-started/integrations/fonts): Plug-and-play web font optimization and configuration - [**Color Mode**](https://ui.nuxt.com/docs/getting-started/integrations/color-mode): Dark and Light mode with auto detection - [**i18n**](https://ui.nuxt.com/docs/getting-started/integrations/i18n): Internationalize your components with 50+ languages - [**Content**](https://ui.nuxt.com/docs/getting-started/integrations/content): Beautiful typography out of the box ### Vue compatibility (Nuxt optional) Nuxt UI works with any Vue project, not just Nuxt. Simply add the Vite and Vue plugins to your configuration: - **Auto-imports**: Components and composables are automatically imported and available globally - **Design System**: Full theming support with customizable colors, sizes, variants, and more - **Developer Experience**: Complete TypeScript support with IntelliSense and auto-completion \> \[!TIP] \> See: /docs/getting-started/installation/vue \> Learn how to install and configure Nuxt UI in a Vue project in the Vue installation guide. ### TypeScript Support Nuxt UI provides comprehensive TypeScript integration for a superior developer experience: - **Auto-completion**: For all component props, slots, and events - **Generic Components**: Using [Vue Generics](https://vuejs.org/api/sfc-script-setup.html#generics){rel=""nofollow""} - **Type-safe Theming**: In `app.config.ts` - **IntelliSense**: Throughout your entire codebase ### Templates Nuxt UI provides production-ready templates for both Nuxt and Vue to help you get started quickly: - **Nuxt templates**: Dashboard, SaaS, Landing, Docs, Portfolio, Chat, Editor, Changelog, and Starter - **Vue templates**: Dashboard and Starter \> \[!TIP] \> See: /templates \> Explore all available templates to kickstart your next project. ## FAQ \*\*Q: Is Nuxt UI free to use?\*\* A: Yes! Nuxt UI is completely free and open source under the MIT license. All 125+ components are available to everyone. \*\*Q: Can I use Nuxt UI with Vue without Nuxt?\*\* A: Yes! While optimized for Nuxt, Nuxt UI works perfectly with standalone Vue projects via our Vite plugin. You can follow the \[installation guide]\(/docs/getting-started/installation/vue) to get started. \*\*Q: Does Nuxt UI include a Figma Kit?\*\* A: Yes! Nuxt UI includes a \[complete Figma Kit]\(https\://go.nuxt.com/figma-ui) with all components, making it easy for designers and developers to collaborate. \*\*Q: How does Nuxt UI handle accessibility?\*\* A: Through \[Reka UI]\(https\://reka-ui.com/docs/overview/accessibility) integration, Nuxt UI provides automatic ARIA attributes, keyboard navigation, focus management, and screen reader support. While offering a strong foundation, testing in your specific use case remains important. \*\*Q: Is Nuxt UI production-ready?\*\* A: Yes! Nuxt UI is used in production by thousands of applications with 1000+ Vitest tests, regular updates, and active maintenance. \*\*Q: When should I consider alternatives?\*\* A: Consider Vuetify if you want Material Design styling, ant-design-vue for Ant Design styling, PrimeVue or Element Plus if you don't want Tailwind CSS, shadcn-vue if you prefer copying components into your repo, Quasar for cross-platform apps (web, mobile, desktop), or Reka UI / Headless UI if you only need unstyled primitives. \*\*Q: Where can I get help?\*\* A: Join our \[Discord community]\(https\://go.nuxt.com/discord) for discussions or report issues on \[GitHub]\(https\://github.com/nuxt/ui/issues). # Installation \> \[!NOTE] \> See: /docs/getting-started/installation/vue \> Looking for the Vue version? ## Setup ### Add to a Nuxt project Install the Nuxt UI package \`\`\`bash pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun add @nuxt/ui tailwindcss \`\`\` Add the Nuxt UI module in your nuxt.config.ts \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'] }) \`\`\` Import Tailwind CSS and Nuxt UI in your CSS \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'], css: \['\~/assets/css/main.css'] }) \`\`\` \> \[!TIP] \> See: https\://nuxt.com/docs/getting-started/layers \> When using \[Nuxt Layers]\(https\://nuxt.com/docs/getting-started/layers), the module automatically generates \[\`@source\`]\(https\://tailwindcss.com/docs/functions-and-directives#source-directive) directives for each layer directory, ensuring Tailwind CSS scans all your layer source files for utility classes. \> \[!NOTE] \> It's recommended to install the \[Tailwind CSS IntelliSense]\(https\://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings: \> \`\`\`json \> { \> "files.associations": { \> "\*.css": "tailwindcss" \> }, \> "editor.quickSuggestions": { \> "strings": "on" \> }, \> "tailwindCSS.classAttributes": \["class", "ui"], \> "tailwindCSS.experimental.classRegex": \[ \> \["\['\\"\`]\(\[^'\\"\`]\*)\['\\"\`]"] \> ] \> } \> \> \`\`\` Wrap your app with App component \`\`\`vue \ \`\`\` \> \[!NOTE] \> See: /docs/components/app \> The \`App\` component provides global configurations and is required for Toast, Tooltip components to work as well as Programmatic Overlays. ### Use a Nuxt template Get started with one of our [official templates](https://ui.nuxt.com/templates) by using the `Use this template` button on GitHub or the CLI: \`\`\`bash npm create nuxt\@latest -- -t ui \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/landing \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/docs \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/saas \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/dashboard \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/chat \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/portfolio \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/changelog \`\`\` \`\`\`bash npm create nuxt\@latest -- -t ui/editor \`\`\` \*\*Starter\*\* A minimal template to get started with Nuxt UI. \*\*Landing\*\* A modern landing page template powered by Nuxt Content. \*\*Docs\*\* A documentation template powered by Nuxt Content. \*\*SaaS\*\* A SaaS template with landing, pricing, docs and blog powered by Nuxt Content. \*\*Dashboard\*\* A dashboard template with multi-column layout for building sophisticated admin interfaces. \*\*Chat\*\* An AI chatbot template to build your own chatbot powered by Vercel AI SDK. \*\*Portfolio\*\* A sleek portfolio template to showcase your work, skills and blog powered by Nuxt Content. \*\*Changelog\*\* A changelog template to display your repository releases notes from GitHub powered by Nuxt MDC. \*\*Editor\*\* A rich text editor template powered by TipTap with support for markdown, HTML, and JSON content types. ## Options You can customize Nuxt UI by providing options in your `nuxt.config.ts`. ### `prefix` Use the `prefix` option to change the prefix of the components. - Default: `U`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { prefix: 'Nuxt' } }) ``` ### `fonts` Use the `fonts` option to enable or disable the [`@nuxt/fonts`](https://github.com/nuxt/fonts){rel=""nofollow""} module. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { fonts: false } }) ``` ### `colorMode` Use the `colorMode` option to enable or disable the [`@nuxt/color-mode`](https://github.com/nuxt-modules/color-mode){rel=""nofollow""} module. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { colorMode: false } }) ``` ### `theme.colors` Use the `theme.colors` option to define the dynamic color aliases used to generate components theme. - Default: `['primary', 'secondary', 'success', 'info', 'warning', 'error']`{.inline,language-ts-type,shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { colors: ['primary', 'error'] } } }) ``` \> \[!TIP] \> See: /docs/getting-started/theme/design-system#colors \> Learn more about color customization and theming in the Theme section. ### `theme.transitions` Use the `theme.transitions` option to enable or disable transitions on components. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { transitions: false } } }) ``` \> \[!NOTE] \> This option adds the \`transition-colors\` class on components with hover or active states. ### `theme.defaultVariants` Use the `theme.defaultVariants` option to override the default `color` and `size` variants for components. - Default: `{ color: 'primary', size: 'md' }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-11} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { theme: { defaultVariants: { color: 'neutral', size: 'sm' } } } }) ``` ### `theme.prefix` `4.2+` Use the `theme.prefix` option to configure the same prefix you set on your Tailwind CSS import. This ensures Nuxt UI components use the correct prefixed utility classes and CSS variables. \`\`\`ts export default defineNuxtConfig({ modules: \['@nuxt/ui'], css: \['\~/assets/css/main.css'], ui: { theme: { prefix: 'tw' } } }) \`\`\` \`\`\`css @import "tailwindcss" prefix(tw); @import "@nuxt/ui"; \`\`\` \> \[!WARNING] \> See: https\://fonts.nuxt.com/get-started/configuration#processcssvariables \> You might need to enable \`fonts.processCSSVariables\` to use the prefix option with the \`@nuxt/fonts\` module: \> \`\`\`ts \> export default defineNuxtConfig({ \> modules: \['@nuxt/ui'], \> css: \['\~/assets/css/main.css'], \> ui: { \> theme: { \> prefix: 'tw' \> } \> }, \> fonts: { \> processCSSVariables: true \> } \> }) \> \> \`\`\` This will automatically prefix all Tailwind utility classes and CSS variables in Nuxt UI component themes: ```html ``` \> \[!NOTE] \> See: https\://tailwindcss.com/docs/styling-with-utility-classes#using-the-prefix-option \> Learn more about using a prefix in the Tailwind CSS documentation. ### `prose` Use the `prose` option to force the import of Nuxt UI `` components even if `@nuxtjs/mdc` or `@nuxt/content` is not installed. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { prose: true } }) ``` ### `mdc` `Deprecated` Use the [`prose`](https://ui.nuxt.com/#prose) option instead. ### `content` Use the `content` option to force the import of Nuxt UI `` and `` components even if `@nuxt/content` is not installed. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [nuxt.config.ts] {4-6} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { content: true } }) ``` ### `experimental.componentDetection` `4.1+` Use the `experimental.componentDetection` option to enable automatic component detection for tree-shaking. This feature scans your source code to detect which components are actually used and only generates the necessary CSS for those components (including their dependencies). - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - Type: `boolean | string[]`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} **Enable automatic detection:** ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { experimental: { componentDetection: true } } }) ``` **Include additional components for dynamic usage:** ```ts [nuxt.config.ts] {4-8} export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { experimental: { componentDetection: ['Modal', 'Dropdown', 'Popover'] } } }) ``` \> \[!NOTE] \> When providing an array of component names, automatic detection is enabled and these components (along with their dependencies) are guaranteed to be included. This is useful for dynamic components like \`\\` that can't be statically analyzed. ## Continuous releases Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new){rel=""nofollow""} for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Automatic preview releases are created for all commits and PRs to the `v4` branch. Use them by replacing your package version with the specific commit hash or PR number. ```diff [package.json] { "dependencies": { - "@nuxt/ui": "^4.0.0", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909", } } ``` \> \[!NOTE] \> pkg.pr.new will automatically comment on PRs with the installation URL, making it easy to test changes. # Installation \> \[!NOTE] \> See: /docs/getting-started/installation/nuxt \> Looking for the Nuxt version? ## Setup ### Add to a Vue project Install the Nuxt UI package \`\`\`bash pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun add @nuxt/ui tailwindcss \`\`\` Add the Nuxt UI Vite plugin in your vite.config.ts \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), ui() ] }) \`\`\` \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' import laravel from 'laravel-vite-plugin' export default defineConfig({ plugins: \[ laravel({ input: \['resources/js/app.ts'], refresh: true }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false } } }), ui({ router: 'inertia' }) ] }) \`\`\` \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' import adonisjs from '@adonisjs/vite/client' import inertia from '@adonisjs/inertia/client' export default defineConfig({ plugins: \[ adonisjs({ entrypoints: \['inertia/app/app.ts'], reload: \['resources/views/\*\*/\*.edge'] }), inertia(), vue(), ui({ router: 'inertia' }) ] }) \`\`\` \> \[!TIP] \> Nuxt UI registers \`unplugin-auto-import\` and \`unplugin-vue-components\`, which will generate \`auto-imports.d.ts\` and \`components.d.ts\` type declaration files. You will likely want to gitignore these, and add them to your \`tsconfig\`. \> \`\`\`json \> { \> "include": \["src/\*\*/\*.ts", "src/\*\*/\*.tsx", "src/\*\*/\*.vue", "auto-imports.d.ts", "components.d.ts"] \> } \> \> \`\`\` \> \> \`\`\`bash \> # Auto-generated type declarations \> auto-imports.d.ts \> components.d.ts \> \> \`\`\` \> \[!TIP] \> Internally, Nuxt UI relies on custom alias to resolve the theme types. If you're using TypeScript, you should add an alias to your \`tsconfig\` to enable auto-completion in your \`vite.config.ts\`. \> \`\`\`json \> { \> "compilerOptions": { \> "paths": { \> "#build/ui": \[ \> "./node\_modules/.nuxt-ui/ui" \> ] \> } \> } \> } \> \> \`\`\` \> \> \`\`\`json \> { \> "compilerOptions": { \> "paths": { \> "#build/ui/\*": \[ \> "./node\_modules/.nuxt-ui/ui/\*" \> ] \> } \> } \> } \> \> \`\`\` Use the Nuxt UI Vue plugin \`\`\`ts 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') \`\`\` \`\`\`ts import type { DefineComponent } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import ui from '@nuxt/ui/vue-plugin' import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers' import { createApp, h } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'Laravel x Nuxt UI' createInertiaApp({ title: title => (title ? \`${title} - ${appName}\` : appName), resolve: name => resolvePageComponent( \`./pages/${name}.vue\`, import.meta.glob\('./pages/\*\*/\*.vue') ), setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .use(ui) .mount(el) } }) \`\`\` \`\`\`ts import type { DefineComponent } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import ui from '@nuxt/ui/vue-plugin' import { resolvePageComponent } from '@adonisjs/inertia/helpers' import { createApp, h } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'AdonisJS x Nuxt UI' createInertiaApp({ title: title => (title ? \`${title} - ${appName}\` : appName), resolve: name => resolvePageComponent( \`../pages/${name}.vue\`, import.meta.glob\('../pages/\*\*/\*.vue') ), setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .use(ui) .mount(el) } }) \`\`\` Import Tailwind CSS and Nuxt UI in your CSS \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` \> \[!TIP] \> Import the CSS file in your entrypoint. \> \`\`\`ts \> import './assets/css/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') \> \> \`\`\` \> \> \`\`\`ts \> import '../css/app.css' \> import type { DefineComponent } from 'vue' \> import { createInertiaApp } from '@inertiajs/vue3' \> import ui from '@nuxt/ui/vue-plugin' \> import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers' \> import { createApp, h } from 'vue' \> \> const appName = import.meta.env.VITE\_APP\_NAME || 'Laravel x Nuxt UI' \> \> createInertiaApp({ \> title: title => (title ? \`${title} - ${appName}\` : appName), \> resolve: name => \> resolvePageComponent( \> \`./pages/${name}.vue\`, \> import.meta.glob\('./pages/\*\*/\*.vue') \> ), \> setup({ el, App, props, plugin }) { \> createApp({ render: () => h(App, props) }) \> .use(plugin) \> .use(ui) \> .mount(el) \> } \> }) \> \> \`\`\` \> \> \`\`\`ts \> import '../css/app.css' \> import type { DefineComponent } from 'vue' \> import { createInertiaApp } from '@inertiajs/vue3' \> import ui from '@nuxt/ui/vue-plugin' \> import { resolvePageComponent } from '@adonisjs/inertia/helpers' \> import { createApp, h } from 'vue' \> \> const appName = import.meta.env.VITE\_APP\_NAME || 'AdonisJS x Nuxt UI' \> \> createInertiaApp({ \> title: title => (title ? \`${title} - ${appName}\` : appName), \> resolve: name => \> resolvePageComponent( \> \`../pages/${name}.vue\`, \> import.meta.glob\('../pages/\*\*/\*.vue') \> ), \> setup({ el, App, props, plugin }) { \> createApp({ render: () => h(App, props) }) \> .use(plugin) \> .use(ui) \> .mount(el) \> } \> }) \> \> \`\`\` \> \[!NOTE] \> It's recommended to install the \[Tailwind CSS IntelliSense]\(https\://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings: \> \`\`\`json \> { \> "files.associations": { \> "\*.css": "tailwindcss" \> }, \> "editor.quickSuggestions": { \> "strings": "on" \> }, \> "tailwindCSS.classAttributes": \["class", "ui"], \> "tailwindCSS.experimental.classRegex": \[ \> \["\['\\"\`]\(\[^'\\"\`]\*)\['\\"\`]"] \> ] \> } \> \> \`\`\` Wrap your app with App component \`\`\`vue \ \`\`\` \`\`\`vue \ \`\`\` \`\`\`vue \ \`\`\` \> \[!NOTE] \> See: /docs/components/app \> The \`App\` component sets up global config and is required for Toast, Tooltip and programmatic overlays. Add the isolate class to your root container \`\`\`html \ \ \ \ \ \Nuxt UI\ \ \ \
\
\ \ \ \`\`\` \`\`\`blade \ \ \ \ \ @inertiaHead @vite('resources/js/app.ts') \ \ \
@inertia \
\ \ \`\`\` \`\`\`edge \ \ \ \ \ @inertiaHead() @vite(\['inertia/app/app.ts', \`inertia/pages/${page.component}.vue\`]) \ \ @inertia({ class: 'isolate' }) \ \ \`\`\` \> \[!NOTE] \> This ensures styles are scoped to your app and prevents issues with overlays and stacking contexts. ### Use a Vue template Get started with one of our [official templates](https://ui.nuxt.com/templates) by using the `Use this template` button on GitHub or the CLI: \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue \`\`\` \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue/dashboard \`\`\` \`\`\`bash npm create nuxt\@latest -- --no-modules -t ui-vue/chat \`\`\` \*\*Starter\*\* A minimal template to get started with Nuxt UI. \*\*Dashboard\*\* A dashboard template with multi-column layout for building sophisticated admin interfaces. \*\*Chat\*\* An AI chatbot template to build your own chatbot powered by Vercel AI SDK. \*\*Starter Adonis\*\* A minimal Nuxt UI template for AdonisJS using Inertia.js. \*\*Starter Laravel\*\* A minimal Nuxt UI template for Laravel using Inertia.js. ## Options You can customize Nuxt UI by providing options in your `vite.config.ts`. ### `prefix` Use the `prefix` option to change the prefix of the components. - Default: `U`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ prefix: 'Nuxt' }) ] }) ``` ### `ui` Use the `ui` option to provide configuration for Nuxt UI. ```ts [vite.config.ts] {9-14} 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: 'green', neutral: 'slate' } } }) ] }) ``` ### `colorMode` Use the `colorMode` option to enable or disable the color mode integration from `@vueuse/core`. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ colorMode: false }) ] }) ``` ### `theme.colors` Use the `theme.colors` option to define the dynamic color aliases used to generate components theme. - Default: `['primary', 'secondary', 'success', 'info', 'warning', 'error']`{.inline,language-ts-type,shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-11} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { colors: ['primary', 'error'] } }) ] }) ``` \> \[!TIP] \> See: /docs/getting-started/theme/design-system#colors \> Learn more about color customization and theming in the Theme section. ### `theme.transitions` Use the `theme.transitions` option to enable or disable transitions on components. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-11} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { transitions: false } }) ] }) ``` \> \[!NOTE] \> This option adds the \`transition-colors\` class on components with hover or active states. ### `theme.defaultVariants` Use the `theme.defaultVariants` option to override the default `color` and `size` variants for components. - Default: `{ color: 'primary', size: 'md' }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9-14} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ theme: { defaultVariants: { color: 'neutral', size: 'sm' } } }) ] }) ``` ### `theme.prefix` `4.2+` Use the `theme.prefix` option to configure the same prefix you set on your Tailwind CSS import. This ensures Nuxt UI components use the correct prefixed utility classes and CSS variables. \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), ui({ theme: { prefix: 'tw' } }) ] }) \`\`\` \`\`\`css @import "tailwindcss" prefix(tw); @import "@nuxt/ui"; \`\`\` This will automatically prefix all Tailwind utility classes and CSS variables in Nuxt UI component themes: ```html ``` \> \[!NOTE] \> See: https\://tailwindcss.com/docs/styling-with-utility-classes#using-the-prefix-option \> Learn more about using a prefix in the Tailwind CSS documentation. ### `prose` Use the `prose` option to enable Nuxt UI `` components and their theme. - Default: `false`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ prose: true }) ] }) ``` ### `autoImport` Use the `autoImport` option to disable composable auto-imports or to customize [`unplugin-auto-import`](https://github.com/unplugin/unplugin-auto-import){rel=""nofollow""} options. - Default: `{}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ autoImport: false }) ] }) ``` \> \[!NOTE] \> When disabled, you can still import composables explicitly from \`@nuxt/ui/composables\`. ### `components` Use the `components` option to disable component auto-imports or to customize [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components){rel=""nofollow""} options. - Default: `{}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ components: false }) ] }) ``` \> \[!NOTE] \> When disabled, you can still import components explicitly, e.g. \`import Button from '@nuxt/ui/components/Button.vue'\` or \`import ProseCode from '@nuxt/ui/components/prose/Code.vue'\`. ### `router` `4.3+` Use the `router` option to configure routing integration. This is useful for applications that don't use `vue-router`, such as Electron apps, MPAs, or frameworks like [Inertia.js](https://inertiajs.com/){rel=""nofollow""} or [Hybridly](https://hybridly.dev/){rel=""nofollow""}. - Default: `true`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} | Value | Description | | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | `true`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Uses `vue-router` for navigation with `RouterLink` component. | | `false`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Disables routing integration, links render as plain `
` tags. | | `'inertia'`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | Uses Inertia.js for navigation with its `Link` component. | ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ router: false }) ] }) ``` \> \[!TIP] \> You can provide custom navigation logic for frameworks like Hybridly by setting \`router: false\` in the Vite config and passing a function when installing the Vue plugin: \> \`\`\`ts \> import ui from '@nuxt/ui/vue-plugin' \> import { router } from 'hybridly' \> \> app.use(ui, { \> router: (event, { href, external }) => { \> if (external) { \> return \> } \> \> event.preventDefault() \> \> router.navigate({ url: href }) \> } \> }) \> \> \`\`\` \> \[!NOTE] \> When set to \`false\` or \`'inertia'\`, \`vue-router\` is not required as a dependency. ### `scanPackages` `4.3+` Use the `scanPackages` option to specify additional npm packages that should be scanned for components using Nuxt UI. This is useful when you have a shared component library that uses Nuxt UI components internally. ```ts [vite.config.ts] {9} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: [ vue(), ui({ scanPackages: ['@my-org/ui-components'] }) ] }) ``` \> \[!NOTE] \> By default, only \`@nuxt/ui\` is scanned. Use this option when your external packages contain Vue components that use Nuxt UI. ## Continuous releases Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new){rel=""nofollow""} for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Automatic preview releases are created for all commits and PRs to the `v4` branch. Use them by replacing your package version with the specific commit hash or PR number. ```diff [package.json] { "dependencies": { - "@nuxt/ui": "^4.0.0", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909", } } ``` \> \[!NOTE] \> pkg.pr.new will automatically comment on PRs with the installation URL, making it easy to test changes. # Migration to v4 Nuxt UI v4 marks a major milestone: **Nuxt UI and Nuxt UI Pro are now unified into a single, fully open-source and free library**. You now have access to 125+ production-ready components, all available in the `@nuxt/ui` package. \> \[!NOTE] \> Nuxt UI v4 requires Nuxt 4 due to some dependencies. Make sure to upgrade to Nuxt 4 before migrating to Nuxt UI v4. This guide provides step-by-step instructions to migrate your application from v3 to v4. ## Migrate your project ### From Nuxt UI Pro 1. Replace `@nuxt/ui-pro` with `@nuxt/ui` in your `package.json`: \`\`\`bash pnpm remove @nuxt/ui-pro pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn remove @nuxt/ui-pro yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm uninstall @nuxt/ui-pro npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun remove @nuxt/ui-pro bun add @nuxt/ui tailwindcss \`\`\` \*\*Nuxt:\*\* Replace @nuxt/ui-pro with @nuxt/ui in your nuxt.config.ts: \`\`\`diff export default defineNuxtConfig({ modules: \[ \- '@nuxt/ui-pro', \+ '@nuxt/ui' ] }) \`\`\` \*\*Vue:\*\* Replace @nuxt/ui-pro with @nuxt/ui in your vite.config.ts: \`\`\`diff import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' \- import uiPro from '@nuxt/ui-pro/vite' \+ import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), \- uiPro({ \+ ui({ ui: { colors: { primary: 'green', neutral: 'slate' } } }) ] }) \`\`\` \*\*Nuxt:\*\* Use the ui key instead of uiPro in your app.config.ts: \`\`\`diff export default defineAppConfig({ ui: { colors: { primary: 'green', neutral: 'slate' }, \+ pageCard: { \+ slots: { \+ root: 'rounded-xl', \+ } \+ } }, \- uiPro: { \- pageCard: { \- slots: { \- root: 'rounded-xl', \- } \- } \- } }) \`\`\` \*\*Vue:\*\* Use the ui key instead of uiPro in your vite.config.ts: \`\`\`diff export default defineConfig({ plugins: \[ vue(), ui({ ui: { colors: { primary: 'green', neutral: 'slate' }, \+ pageCard: { \+ slots: { \+ root: 'rounded-xl', \+ } \+ } }, \- uiPro: { \- pageCard: { \- slots: { \- root: 'rounded-xl', \- } \- } \- } }) ] }) \`\`\` 4. Replace `@nuxt/ui-pro` with `@nuxt/ui` in your CSS: \*\*Nuxt:\*\* \`\`\`diff @import "tailwindcss"; \- @import "@nuxt/ui-pro"; \+ @import "@nuxt/ui"; \`\`\` \> \[!WARNING] \> If you are upgrading to Nuxt 4 at the same time as Nuxt UI v4, make sure to update the \`@source\` directive to match the new directory structure. \> \`\`\`diff \> @import "tailwindcss"; \> @import "@nuxt/ui"; \> \> - @source "../../content/\*\*/\*"; \> + @source "../../../content/\*\*/\*"; \> \> \`\`\` \*\*Vue:\*\* \`\`\`diff @import "tailwindcss"; \- @import "@nuxt/ui-pro"; \+ @import "@nuxt/ui"; \`\`\` 5. Replace `@nuxt/ui-pro` with `@nuxt/ui` in your imports: ```diff - import type { BannerProps } from '@nuxt/ui-pro' + import type { BannerProps } from '@nuxt/ui' ``` ### From Nuxt UI 1. When upgrading from Nuxt UI v3, you simply need to update to v4: \`\`\`bash pnpm add @nuxt/ui tailwindcss \`\`\` \`\`\`bash yarn add @nuxt/ui tailwindcss \`\`\` \`\`\`bash npm install @nuxt/ui tailwindcss \`\`\` \`\`\`bash bun add @nuxt/ui tailwindcss \`\`\` ## Changes from v3 After upgrading to Nuxt UI v4, please note the following important changes: ### Renamed ButtonGroup The `ButtonGroup` component has been renamed to [`FieldGroup`](https://ui.nuxt.com/docs/components/field-group): ```diff ``` ### Renamed PageMarquee The `PageMarquee` component has been renamed to [`Marquee`](https://ui.nuxt.com/docs/components/marquee): ```diff ``` ### Removed PageAccordion The `PageAccordion` component has been removed in favor of [`Accordion`](https://ui.nuxt.com/docs/components/accordion): ```diff ``` \> \[!NOTE] \> The \`PageAccordion\` component was a wrapper that set \`unmount-on-hide\` to \`false\` and customized the \`ui\` prop. ### Renamed model modifiers The `modelModifiers` shape used by [`Input`](https://ui.nuxt.com/docs/components/input), [`InputNumber`](https://ui.nuxt.com/docs/components/input-number) and [`Textarea`](https://ui.nuxt.com/docs/components/textarea) has changed in v4: 1. The `nullify` modifier was renamed to `nullable` (it converts empty/blank values to `null`). 2. A new `optional` modifier was added (it converts empty/blank values to `undefined`). ```diff - + ``` ```diff - + ``` Use `nullable` when you want empty values as `null`, and `optional` when you prefer `undefined` for absent values. ### Changes to Form component The `Form` component has been improved in v4 with better state management and nested form handling. Here are the key changes you need to be aware of: 1. Schema **transformations will only** be applied to the **`@submit` data** and will no longer mutate the form's state. This provides better predictability and prevents unexpected state mutations. 2. **Nested forms must be enabled explicitly** using the `nested` prop. This makes the component behavior more explicit and prevents accidental nested form creation. 3. **Nested forms should now provide a `name`** prop (similar to `UFormField`) and will automatically inherit their state from their parent form. ```diff ``` ### Removed deprecated utilities Some **Nuxt Content utilities** that were previously available in Nuxt UI Pro have been **removed** in v4: - `findPageBreadcrumb` - `findPageHeadline` These are now fully provided by Nuxt Content. Make sure to update your imports and usage accordingly. ```diff - import { findPageHeadline } from '@nuxt/ui-pro/utils/content' + import { findPageHeadline } from '@nuxt/content/utils' - import { findPageBreadcrumb } from '@nuxt/ui-pro/utils/content' + import { findPageBreadcrumb } from '@nuxt/content/utils' ``` ### AI SDK v5 migration (optional) This section only applies if you're using the AI SDK and chat components (`ChatMessage`, `ChatMessages`, `ChatPrompt`, `ChatPromptSubmit`, `ChatPalette`). If you're not using AI features, you can skip this section. 1. Update `@ai-sdk/vue` and `ai` dependencies in your `package.json`: ```diff { "dependencies": { - "@ai-sdk/vue": "^1.2.x", + "@ai-sdk/vue": "^2.0.x", - "ai": "^4.3.x" + "ai": "^5.0.x" } } ``` 2. `useChat` composable has been replaced with the new `Chat` class: ```diff ``` 3. Messages now use `parts` instead of `content`: ```diff // When manually creating messages - setMessages([{ + messages.push({ id: '1', role: 'user', - content: 'Hello world' + parts: [{ type: 'text', text: 'Hello world' }] - }]) + }) // In templates ``` 4. Some methods have been renamed: ```diff // Regenerate the last message - reload() + chat.regenerate() // Access chat state - :messages="messages" - :status="status" + :messages="chat.messages" + :status="chat.status" ``` 5. Parts-based rendering with AI SDK helpers and `isReasoningStreaming` utility from `@nuxt/ui/utils/ai`: ```vue ``` \> \[!NOTE] \> See: https\://ai-sdk.dev/docs/migration-guides/migration-guide-5-0 \> For more details on AI SDK v5 changes, review the official AI SDK v5 migration guide. \> \[!TIP] \> See: https\://github.com/nuxt/ui/pull/4698 \> View all changes from AI SDK v4 to v5 in the upgrade PR for a detailed migration reference. # Migration to v3 Nuxt UI v3 is a new major version rebuilt from the ground up, introducing a modern architecture with significant performance improvements and an enhanced developer experience. This major release includes several breaking changes alongside powerful new features and capabilities: - **Tailwind CSS v4**: Migration from JavaScript to CSS-based configuration - **Reka UI**: Replacing Headless UI as the underlying component library - **Tailwind Variants**: New styling API for component variants This guide provides step by step instructions to migrate your application from v2 to v3. ## Migrate your project Update Tailwind CSSTailwind CSS v4 introduces significant changes to its configuration approach. The official Tailwind upgrade tool will help automate most of the migration process. \> \[!NOTE] \> See: https\://tailwindcss.com/docs/upgrade-guide#changes-from-v3 \> For a detailed walkthrough of all changes, refer to the official Tailwind CSS v4 upgrade guide. Create a main.css file and import it in your nuxt.config.ts file: \`\`\`css @import "tailwindcss"; \`\`\` \`\`\`ts export default defineNuxtConfig({ css: \['\~/assets/css/main.css'] }) \`\`\` Run the Tailwind CSS upgrade tool: \`\`\`bash npx @tailwindcss/upgrade \`\`\` Update Nuxt UIInstall the latest version of the package: \`\`\`bash pnpm add @nuxt/ui \`\`\` \`\`\`bash yarn add @nuxt/ui \`\`\` \`\`\`bash npm install @nuxt/ui \`\`\` \`\`\`bash bun add @nuxt/ui \`\`\` Import it in your CSS: \`\`\`css @import "tailwindcss"; @import "@nuxt/ui"; \`\`\` Wrap your app with the App component: \`\`\`vue \ \`\`\` ## Changes from v2 Now that you have updated your project, you can start migrating your code. Here's a comprehensive list of all the breaking changes in Nuxt UI v3. ### Updated design system In Nuxt UI v2, we had a mix between a design system with `primary`, `gray`, `error` aliases and all the colors from Tailwind CSS. We've replaced it with a proper [design system](https://ui.nuxt.com/docs/getting-started/theme/design-system) with 7 color aliases: | Color | Default | Description | | ------------------------------ | -------- | ----------------------------------------------------------- | | `primary`{color="primary"} | `green` | Main brand color, used as the default color for components. | | `secondary`{color="secondary"} | `blue` | Secondary color to complement the primary color. | | `success`{color="success"} | `green` | Used for success states. | | `info`{color="info"} | `blue` | Used for informational states. | | `warning`{color="warning"} | `yellow` | Used for warning states. | | `error`{color="error"} | `red` | Used for form error validation states. | | `neutral` | `slate` | Neutral color for backgrounds, text, etc. | This change introduces several breaking changes that you need to be aware of: - The `gray` color has been renamed to `neutral` ```diff ``` \> \[!NOTE] \> You can also use the new \[design tokens]\(/docs/getting-started/theme/css-variables) to handle light and dark mode: \> \`\`\`diff \> \ \> \> \`\`\` - The `gray`, `black` and `white` in the `color` props have been removed in favor of `neutral`: ```diff - + - + - + ``` - You can no longer use Tailwind CSS colors in the `color` props, use the new aliases instead: ```diff - + ``` \> \[!NOTE] \> See: /docs/getting-started/theme/design-system#colors \> Learn how to extend the design system to add new color aliases. - The color configuration in `app.config.ts` has been moved into a `colors` object: ```diff export default defineAppConfig({ ui: { - primary: 'green', - gray: 'cool' + colors: { + primary: 'green', + neutral: 'slate' + } } }) ``` ### Updated theming system Nuxt UI components are now styled using the [Tailwind Variants API](https://ui.nuxt.com/docs/getting-started/theme/components), which makes all the overrides you made using the `app.config.ts` and the `ui` prop obsolete. - Update your [`app.config.ts`](https://ui.nuxt.com/docs/getting-started/theme/components#global-config) to override components with their new theme: ```diff export default defineAppConfig({ ui: { button: { - font: 'font-bold', - default: { - size: 'md', - color: 'primary' - } + slots: { + base: 'font-medium' + }, + defaultVariants: { + size: 'md', + color: 'primary' + } } } }) ``` - Update your [`ui` props](https://ui.nuxt.com/docs/getting-started/theme/components#ui-prop) to override each component's slots using their new theme: ```diff ``` \> \[!TIP] \> See: /docs/components/button#theme \> We can't detail all the changes here but you can check each component's theme in the Theme section. ### Renamed components We've renamed some Nuxt UI components to align with the Reka UI naming convention: | v2 | v3 | | ---------------------- | ------------------------------------------------------------------------------------------------------- | | `Divider` | [`Separator`](https://ui.nuxt.com/docs/components/separator) | | `Dropdown` | [`DropdownMenu`](https://ui.nuxt.com/docs/components/dropdown-menu) | | `FormGroup` | [`FormField`](https://ui.nuxt.com/docs/components/form-field) | | `Range` | [`Slider`](https://ui.nuxt.com/docs/components/slider) | | `Toggle` | [`Switch`](https://ui.nuxt.com/docs/components/switch) | | `Meter` | Removed | | `Notification` | [`Toast`](https://ui.nuxt.com/docs/components/toast) | | `Radio` | Removed (use [`RadioGroup`](https://ui.nuxt.com/docs/components/radio-group) instead) | | `VerticalNavigation` | [`NavigationMenu`](https://ui.nuxt.com/docs/components/navigation-menu) with `orientation="vertical"` | | `HorizontalNavigation` | [`NavigationMenu`](https://ui.nuxt.com/docs/components/navigation-menu) with `orientation="horizontal"` | Here are the Nuxt UI Pro components that have been renamed or removed: | v1 | v3 | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `BlogList` | [`BlogPosts`](https://ui.nuxt.com/docs/components/blog-posts) | | `ColorModeToggle` | [`ColorModeSwitch`](https://ui.nuxt.com/docs/components/color-mode-switch) | | `DashboardCard` | Removed (use [`PageCard`](https://ui.nuxt.com/docs/components/page-card) instead) | | `DashboardLayout` | [`DashboardGroup`](https://ui.nuxt.com/docs/components/dashboard-group) | | `DashboardModal` | Removed (use [`Modal`](https://ui.nuxt.com/docs/components/modal) instead) | | `DashboardNavbarToggle` | [`DashboardSidebarToggle`](https://ui.nuxt.com/docs/components/dashboard-sidebar-toggle) | | `DashboardPage` | Removed | | `DashboardPanelContent` | Removed (use `#body` slot instead) | | `DashboardPanelHandle` | [`DashboardResizeHandle`](https://ui.nuxt.com/docs/components/dashboard-resize-handle) | | `DashboardSection` | Removed (use [`PageCard`](https://ui.nuxt.com/docs/components/page-card) instead) | | `DashboardSidebarLinks` | Removed (use [`NavigationMenu`](https://ui.nuxt.com/docs/components/navigation-menu) instead) | | `DashboardSlideover` | Removed (use [`Slideover`](https://ui.nuxt.com/docs/components/slideover) instead) | | `FooterLinks` | Removed (use [`NavigationMenu`](https://ui.nuxt.com/docs/components/navigation-menu) instead) | | `HeaderLinks` | Removed (use [`NavigationMenu`](https://ui.nuxt.com/docs/components/navigation-menu) instead) | | `LandingCard` | Removed (use [`PageCard`](https://ui.nuxt.com/docs/components/page-card) instead) | | `LandingCTA` | [`PageCTA`](https://ui.nuxt.com/docs/components/page-cta) | | `LandingFAQ` | Removed (use [`Accordion`](https://ui.nuxt.com/docs/components/accordion) instead) | | `LandingGrid` | Removed (use [`PageGrid`](https://ui.nuxt.com/docs/components/page-grid) instead) | | `LandingHero` | Removed (use [`PageHero`](https://ui.nuxt.com/docs/components/page-hero) instead) | | `LandingLogos` | [`PageLogos`](https://ui.nuxt.com/docs/components/page-logos) | | `LandingSection` | [`PageSection`](https://ui.nuxt.com/docs/components/page-section) | | `LandingTestimonial` | Removed (use [`PageCard`](https://ui.nuxt.com/docs/components/page-card#as-a-testimonial) instead) | | `NavigationAccordion` | [`ContentNavigation`](https://ui.nuxt.com/docs/components/content-navigation) | | `NavigationLinks` | [`ContentNavigation`](https://ui.nuxt.com/docs/components/content-navigation) | | `NavigationTree` | [`ContentNavigation`](https://ui.nuxt.com/docs/components/content-navigation) | | `PageError` | [`Error`](https://ui.nuxt.com/docs/components/error) | | `PricingCard` | [`PricingPlan`](https://ui.nuxt.com/docs/components/pricing-plan) | | `PricingGrid` | [`PricingPlans`](https://ui.nuxt.com/docs/components/pricing-plans) | | `PricingSwitch` | Removed (use [`Switch`](https://ui.nuxt.com/docs/components/switch) or [`Tabs`](https://ui.nuxt.com/docs/components/tabs) instead) | ### Changed components In addition to the renamed components, there are lots of changes to the components API. Let's detail the most important ones: - The `links` and `options` props have been renamed to `items` for consistency: ```diff ``` \> \[!NOTE] \> This change affects the following components: \`Breadcrumb\`, \`HorizontalNavigation\`, \`InputMenu\`, \`RadioGroup\`, \`Select\`, \`SelectMenu\`, \`VerticalNavigation\`. - The `click` field in different components has been removed in favor of the native Vue `onClick` event: ```diff ``` \> \[!NOTE] \> This change affects the \`Toast\` component as well as all component that have \`items\` links like \`NavigationMenu\`, \`DropdownMenu\`, \`CommandPalette\`, etc. - The global `Modals`, `Slideovers` and `Notifications` components have been removed in favor of the [App](https://ui.nuxt.com/docs/components/app) component: ```diff [app.vue] ``` - The `v-model:open` directive and `default-open` prop are now used to control visibility: ```diff ``` \> \[!NOTE] \> This change affects the following components: \`ContextMenu\`, \`Modal\` and \`Slideover\` and enables controlling visibility for \`InputMenu\`, \`Select\`, \`SelectMenu\` and \`Tooltip\`. - The default slot is now used for the trigger and the content goes inside the `#content` slot (you don't need to use a `v-model:open` directive with this method): ```diff ``` \> \[!NOTE] \> This change affects the following components: \`Modal\`, \`Popover\`, \`Slideover\`, \`Tooltip\`. - A `#header`, `#body` and `#footer` slots have been added inside the `#content` slot like: ```diff ``` \> \[!NOTE] \> This change affects the following components: \`Modal\`, \`Slideover\`. - The `prevent-close` prop has been removed in favor of the `dismissible` prop: ```diff ``` \> \[!NOTE] \> This change affects the following components: \`Modal\`, \`Slideover\`. - The `Pagination` component `v-model` directive has been renamed to `v-model:page`: ```diff ``` - The `change` event now emits the native `change` event, not the new value, which is now emitted in the `update:modelValue` event: ```diff ``` \> \[!NOTE] \> This change affects the following components: \`Select\`, \`SelectMenu\`, \`RadioGroup\`. - The `SelectMenu` component `searchable` prop has been renamed to `search-input` and now defaults to `true`. To preserve v2 behavior (no search input): ```diff ``` - The `Accordion` component has been redesigned. The `multiple` prop has been replaced by the `type` prop (defaults to `single`): ```diff ``` - The `Accordion` component `default-open` prop and `defaultOpen` **item** property have been removed. State is now controlled using `default-value` (uncontrolled) or `v-model` (controlled): ```diff ``` - The `Accordion` component `#item` slot has been removed in favor of `#content` and `#body`: ```diff ``` \> \[!NOTE] \> The default slot now only customizes the trigger, with additional slots for finer control (\`#leading\`, \`#trailing\`, \`#body\`). - The `Accordion` component `unmount` prop has been renamed to `unmount-on-hide` and now defaults to `true`. To preserve v2 behavior (keep content mounted), use `:unmount-on-hide="false"`: ```diff ``` - The `Table` component now uses [TanStack Table](https://tanstack.com/table/latest){rel=""nofollow""} under the hood. The `rows` prop has been renamed to `data`: ```diff ``` - The `Table` component columns definition is now explicit and semantic: ```diff ``` - The `Table` component row cell slot names have been changed from `-data` to `-cell`: ```diff ``` These utility classes are calculated based on a global `--ui-radius` CSS variable, which defines the base radius value applied across all components for a consistent look. ```css :root { --ui-radius: 0.25rem; } ``` \> \[!TIP] \> You can customize the base radius value in your \`main.css\` file: \> \`\`\`css \> @import "tailwindcss"; \> @import "@nuxt/ui"; \> \> \:root { \> --ui-radius: 0.5rem; \> } \> \> \`\`\` \> \[!NOTE] \> Try the theme picker in the header above to change the base radius value. ## Container Nuxt UI provides a `--ui-container` CSS variable that controls the maximum width of the [Container](https://ui.nuxt.com/docs/components/container) component. ```css :root { --ui-container: 80rem; /* var(--container-7xl) */ } ``` \> \[!TIP] \> You can customize this value in your \`main.css\` file to adjust container widths consistently throughout your application: \> \`\`\`css \> @import "tailwindcss"; \> @import "@nuxt/ui"; \> \> @theme { \> --container-8xl: 90rem; \> } \> \> \:root { \> --ui-container: var(--container-8xl); \> } \> \> \`\`\` ## Header Nuxt UI provides a `--ui-header-height` CSS variable that controls the height of the [Header](https://ui.nuxt.com/docs/components/header) component. ```css :root { --ui-header-height: 4rem; } ``` \> \[!TIP] \> You can customize this value in your \`main.css\` to adjust header height consistently throughout your application: \> \`\`\`css \> @import "tailwindcss"; \> @import "@nuxt/ui"; \> \> \:root { \> --ui-header-height: --spacing(24); \> } \> \> \`\`\` ## Body Nuxt UI applies default classes on the ``{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="html"} element of your app for consistent theming across light and dark modes: ```css body { @apply antialiased text-default bg-default scheme-light dark:scheme-dark; } ``` # Customize components ## Tailwind Variants Nuxt UI components are styled using the [Tailwind Variants](https://www.tailwind-variants.org/){rel=""nofollow""} API, which provides a powerful way to create variants and manage component styles. ### Slots Components can have multiple `slots`, each representing a distinct HTML element or section within the component. These slots allow for flexible content insertion and styling. Let's take the [Card](https://ui.nuxt.com/docs/components/card) component as an example which has multiple slots: \`\`\`ts export default { slots: { root: 'bg-default ring ring-default divide-y divide-default rounded-lg', header: 'p-4 sm\:px-6', body: 'p-4 sm\:p-6', footer: 'p-4 sm\:px-6' } } \`\`\` \`\`\`vue \ \`\`\` Some components don't have slots, they are just composed of a single root element. In this case, the theme only defines the `base` slot like the [Container](https://ui.nuxt.com/docs/components/container) component for example: \`\`\`ts export default { base: 'max-w-(--ui-container) mx-auto px-4 sm\:px-6 lg\:px-8' } \`\`\` \`\`\`vue \ \`\`\` \> \[!WARNING] \> Components without slots don't have a \[\`ui\` prop]\(#ui-prop), only the \[\`class\` prop]\(#class-prop) is available to override styles. ### Variants Components support `variants`, which allow you to dynamically adjust the styles of different `slots` based on component props. For example, the [Avatar](https://ui.nuxt.com/docs/components/avatar) component uses a `size` variant to control its appearance: ```ts [src/theme/avatar.ts] {6-18} export default { slots: { root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated', image: 'h-full w-full rounded-[inherit] object-cover' }, variants: { size: { sm: { root: 'size-7 text-sm' }, md: { root: 'size-8 text-base' }, lg: { root: 'size-9 text-lg' } } }, defaultVariants: { size: 'md' } } ``` This way, the `size` prop will apply the corresponding styles to the `root` slot: ```vue ``` ### Default Variants The `defaultVariants` property sets the default value for each variant when no prop is passed. For example, the [Avatar](https://ui.nuxt.com/docs/components/avatar) component has its default size set to `md`: ```ts [src/theme/avatar.ts] {19-21} export default { slots: { root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated', image: 'h-full w-full rounded-[inherit] object-cover' }, variants: { size: { sm: { root: 'size-7 text-sm' }, md: { root: 'size-8 text-base' }, lg: { root: 'size-9 text-lg' } } }, defaultVariants: { size: 'md' } } ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/installation/nuxt#themedefaultvariants \> You can use the \`theme.defaultVariants\` option in your \`nuxt.config.ts\` to override the default values for \`size\` and \`color\` for all components at once. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/installation/vue#themedefaultvariants \> You can use the \`theme.defaultVariants\` option in your \`vite.config.ts\` to override the default values for \`size\` and \`color\` for all components at once. ### Compound Variants Some components use the `compoundVariants` property to apply classes when multiple variant conditions are met at the same time. For example, the [Button](https://ui.nuxt.com/docs/components/button) component uses the `compoundVariants` property to apply classes for a specific `color` and `variant` combination: ```ts [src/theme/button.ts] {27-31} import type { ModuleOptions } from '../module' export default (options: Required) => ({ slots: { base: ['rounded-md font-medium inline-flex items-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75', options.theme.transitions && 'transition-colors'] }, variants: { color: { ...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])), neutral: '' }, variant: { solid: '', outline: '', soft: '', subtle: '', ghost: '', link: '' } }, compoundVariants: [ ...(options.theme.colors || []).map((color: string) => ({ color, variant: 'outline', class: `ring ring-inset ring-${color}/50 text-${color} hover:bg-${color}/10 active:bg-${color}/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus:outline-none focus-visible:ring-2 focus-visible:ring-${color}` })), { color: 'neutral', variant: 'outline', class: 'ring ring-inset ring-accented text-default bg-default hover:bg-elevated active:bg-elevated disabled:bg-default aria-disabled:bg-default focus:outline-none focus-visible:ring-2 focus-visible:ring-inverted' } ], defaultVariants: { color: 'primary', variant: 'solid' } }) ``` ## Customize theme You have multiple ways to customize the appearance of Nuxt UI components, you can do it for all components at once or on a per-component basis. \> \[!NOTE] \> Tailwind Variants uses \[\`tailwind-merge\`]\(https\://github.com/dcastil/tailwind-merge) under the hood to merge classes so you don't have to worry about conflicting classes. \> \[!TIP] \> You can explore the theme for each component in two ways\:Check the \`Theme\` section in the documentation of each individual component.Browse the source code directly in the GitHub repository at \[\`src/theme\`]\(https\://github.com/nuxt/ui/tree/v4/src/theme). ### Global config \*\*Nuxt:\*\* You can override the theme of components globally inside your app.config.ts by using the exact same structure as the theme object. \*\*Vue:\*\* You can override the theme of components globally inside your vite.config.ts by using the exact same structure as the theme object. You can customize the [`slots`](https://ui.nuxt.com/#slots), [`variants`](https://ui.nuxt.com/#variants), [`compoundVariants`](https://ui.nuxt.com/#compound-variants) and [`defaultVariants`](https://ui.nuxt.com/#default-variants) of a component to change the default theme of a component: \*\*Nuxt:\*\* \`\`\`ts export default defineAppConfig({ ui: { button: { slots: { base: 'font-bold' }, variants: { size: { md: { leadingIcon: 'size-4' } } }, compoundVariants: \[{ color: 'neutral', variant: 'outline', class: 'ring-default hover\:bg-accented' }], defaultVariants: { color: 'neutral', variant: 'outline' } } } }) \`\`\` \*\*Vue:\*\* \`\`\`ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' export default defineConfig({ plugins: \[ vue(), ui({ ui: { button: { slots: { base: 'font-bold' }, variants: { size: { md: { leadingIcon: 'size-4' } } }, compoundVariants: \[{ color: 'neutral', variant: 'outline', class: 'ring-default hover\:bg-accented' }], defaultVariants: { color: 'neutral', variant: 'outline' } } } }) ] }) \`\`\` \> \[!NOTE] \> In this example, \`font-bold\` overrides \`font-medium\` on all buttons, \`size-4\` overrides \`size-5\` class on the leading icon when \`size="md"\` and \`ring-default hover\:bg-accented\` overrides \`ring-accented hover\:bg-elevated\` when \`color="neutral"\` and \`variant="outline"\`. The buttons now defaults to \`color="neutral"\` and \`variant="outline"\`. ### `ui` prop You can also override a component's **slots** using the `ui` prop. This takes priority over both global config and resolved `variants`. ```vue ``` \> \[!NOTE] \> In this example, the \`trailingIcon\` slot is overwritten with \`size-3\` even though the \`md\` size variant would apply a \`size-5\` class to it. ### `class` prop The `class` prop allows you to override the classes of the `root` or `base` slot. This takes priority over both global config and resolved `variants`. ```vue ``` \> \[!NOTE] \> In this example, the \`font-bold\` class will override the default \`font-medium\` class on this button. # Icons \> \[!NOTE] \> See: /docs/getting-started/integrations/icons/vue \> Looking for the Vue version? ## Usage Nuxt UI automatically registers the [`@nuxt/icon`](https://github.com/nuxt/icon){rel=""nofollow""} module for you, so there's no additional setup required. ### Icon component You can use the [Icon](https://ui.nuxt.com/docs/components/icon) component with a `name` prop to display an icon: ```vue ``` \> \[!NOTE] \> You can use any name from the \[https\://icones.js.org]\(https\://icones.js.org) collection. ### Component props Some components also have an `icon` prop to display an icon, like the [Button](https://ui.nuxt.com/docs/components/button) for example: ```vue ``` ## Collections ### Iconify dataset It's highly recommended to install the icon data locally with: \`\`\`bash pnpm i @iconify-json/{collection\_name} \`\`\` \`\`\`bash yarn add @iconify-json/{collection\_name} \`\`\` \`\`\`bash npm install @iconify-json/{collection\_name} \`\`\` For example, to use the `i-uil-github` icon, install its collection with `@iconify-json/uil`. This way the icons can be served locally or from your serverless functions, which is faster and more reliable on both SSR and client-side. \> \[!NOTE] \> See: https\://github.com/nuxt/icon?tab=readme-ov-file#iconify-dataset \> Read more about this in the \`@nuxt/icon\` documentation. ### Custom local collections You can use local SVG files to create a custom Iconify collection. For example, place your icons' SVG files under a folder of your choice, for example, `./app/assets/icons`: ```bash assets/icons ├── add.svg └── remove.svg ``` In your `nuxt.config.ts`, add an item in `icon.customCollections`: ```ts export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], icon: { customCollections: [{ prefix: 'custom', dir: './app/assets/icons' }] } }) ``` Then you can use the icons like this: ```vue ``` \> \[!NOTE] \> See: https\://github.com/nuxt/icon?tab=readme-ov-file#custom-local-collections \> Read more about this in the \`@nuxt/icon\` documentation. ## Theme You can change the default icons used by components in your `app.config.ts`: \*See the interactive theme picker on the documentation website.\* # Icons \> \[!NOTE] \> See: /docs/getting-started/integrations/icons/nuxt \> Looking for the Nuxt version? ## Usage ### Icon component You can use the [Icon](https://ui.nuxt.com/docs/components/icon) component with a `name` prop to display an icon: ```vue ``` \> \[!NOTE] \> You can use any name from the \[https\://icones.js.org]\(https\://icones.js.org) collection. \> \[!WARNING] \> When using collections with a dash (\`-\`), you need to separate the icon name from the collection name with a colon (\`:\`) as \`@iconify/vue\` does not handle this case like \`@nuxt/icon\`. For example, instead of \`i-simple-icons-github\` you need to write \`i-simple-icons\:github\` or \`simple-icons\:github\`.Learn more about the \[Iconify naming convention]\(https\://iconify.design/docs/icon-components/vue/#icon). ### Component props Some components also have an `icon` prop to display an icon, like the [Button](https://ui.nuxt.com/docs/components/button) for example: ```vue ``` ## Theme You can change the default icons used by Nuxt UI components in your `vite.config.ts`: \*See the interactive theme picker on the documentation website.\* # Fonts ## Usage Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/fonts){rel=""nofollow""} module for you, so there's no additional setup required. ### Declaration To use a font in your Nuxt UI application, you can simply declare it in your CSS. It will be automatically loaded and optimized for you. ```css [app/assets/css/main.css] @import "tailwindcss"; @import "@nuxt/ui"; @theme { --font-sans: 'Public Sans', sans-serif; } ``` ### Configuration You can disable the `@nuxt/fonts` module with the `ui.fonts` option in your `nuxt.config.ts`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ ui: { fonts: false } }) ``` # Color Mode \> \[!NOTE] \> See: /docs/getting-started/integrations/color-mode/vue \> Looking for the Vue version? ## Usage Nuxt UI automatically registers the [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode){rel=""nofollow""} module for you, so there's no additional setup required. ### Components You can use the built-in [ColorModeAvatar](https://ui.nuxt.com/docs/components/color-mode-avatar) or [ColorModeImage](https://ui.nuxt.com/docs/components/color-mode-image) components to display different images for light and dark mode and the [ColorModeButton](https://ui.nuxt.com/docs/components/color-mode-button), [ColorModeSwitch](https://ui.nuxt.com/docs/components/color-mode-switch) or [ColorModeSelect](https://ui.nuxt.com/docs/components/color-mode-select) components to switch between light and dark modes. You can also use the [useColorMode](https://color-mode.nuxtjs.org/#usage){rel=""nofollow""} composable to build your own custom component: ```vue [ColorModeButton.vue] ``` ### Configuration You can disable the `@nuxtjs/color-mode` module with the `ui.colorMode` option in your `nuxt.config.ts`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ modules: ['@nuxt/ui'], css: ['~/assets/css/main.css'], ui: { colorMode: false } }) ``` # Color Mode \> \[!NOTE] \> See: /docs/getting-started/integrations/color-mode/nuxt \> Looking for the Nuxt version? ## Usage Nuxt UI automatically registers the [useDark](https://vueuse.org/core/useDark){rel=""nofollow""} composable as a Vue plugin, so there's no additional setup required. ### Components You can use the built-in [ColorModeAvatar](https://ui.nuxt.com/docs/components/color-mode-avatar) or [ColorModeImage](https://ui.nuxt.com/docs/components/color-mode-image) components to display different images for light and dark mode and the [ColorModeButton](https://ui.nuxt.com/docs/components/color-mode-button), [ColorModeSwitch](https://ui.nuxt.com/docs/components/color-mode-switch) or [ColorModeSelect](https://ui.nuxt.com/docs/components/color-mode-select) components to switch between light and dark modes. You can also use the [useColorMode](https://vueuse.org/core/useColorMode){rel=""nofollow""} composable to build your own custom component: ```vue [ColorModeButton.vue] ``` ### Configuration You can disable this plugin with the `colorMode` option in your `vite.config.ts`: ```ts [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({ colorMode: false }) ] }) ``` # Internationalization (i18n) \> \[!NOTE] \> See: /docs/getting-started/integrations/i18n/vue \> Looking for the Vue version? ## Usage \> \[!NOTE] \> See: /docs/components/app \> Nuxt UI provides an App component that wraps your app to provide global configurations, including the \`locale\` prop. ### Locale Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`: ```vue [app.vue] ``` \> \[!TIP] \> Each locale has a \`code\` property (e.g., \`en\`, \`en-GB\`, \`fr\`) that determines the date/time format in components like \[Calendar]\(/docs/components/calendar), \[InputDate]\(/docs/components/input-date) and \[InputTime]\(/docs/components/input-time). ### Custom locale You can create your own locale using the [defineLocale](https://ui.nuxt.com/docs/composables/define-locale) utility: ```vue [app.vue] ``` \> \[!TIP] \> Look at the \`code\` parameter, there you need to pass the iso code of the language. Example:\`hi\` Hindi (language)\`de-AT\`: German (language) as used in Austria (region) ### Extend locale You can customize an existing locale by overriding its `messages` or `code` using the [extendLocale](https://ui.nuxt.com/docs/composables/extend-locale) utility: ```vue [app.vue] ``` ### Dynamic locale To dynamically switch between languages, you can use the [Nuxt I18n](https://i18n.nuxtjs.org/){rel=""nofollow""} module. Install the Nuxt I18n package \`\`\`bash pnpm add @nuxtjs/i18n \`\`\` \`\`\`bash yarn add @nuxtjs/i18n \`\`\` \`\`\`bash npm install @nuxtjs/i18n \`\`\` \`\`\`bash bun add @nuxtjs/i18n \`\`\` Add the Nuxt I18n module in your nuxt.config.ts \`\`\`ts export default defineNuxtConfig({ modules: \[ '@nuxt/ui', '@nuxtjs/i18n' ], css: \['\~/assets/css/main.css'], i18n: { locales: \[{ code: 'de', name: 'Deutsch' }, { code: 'en', name: 'English' }, { code: 'fr', name: 'Français' }] } }) \`\`\` Set the locale prop using useI18n \`\`\`vue \ \ \`\`\` ### Dynamic direction Each locale has a `dir` property which will be used by the `App` component to set the directionality of all components. In a multilingual application, you might want to set the `lang` and `dir` attributes on the `` element dynamically based on the user's locale, which you can do with the [useHead](https://nuxt.com/docs/api/composables/use-head){rel=""nofollow""} composable: ```vue [app.vue] ``` ## Supported languages \*See the full list of supported languages on the documentation website.\* # Internationalization (i18n) \> \[!NOTE] \> See: /docs/getting-started/integrations/i18n/nuxt \> Looking for the Nuxt version? ## Usage \> \[!NOTE] \> See: /docs/components/app \> Nuxt UI provides an App component that wraps your app to provide global configurations, including the \`locale\` prop. ### Locale Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`: ```vue [App.vue] ``` \> \[!TIP] \> Each locale has a \`code\` property (e.g., \`en\`, \`en-GB\`, \`fr\`) that determines the date/time format in components like \[Calendar]\(/docs/components/calendar), \[InputDate]\(/docs/components/input-date) and \[InputTime]\(/docs/components/input-time). ### Custom locale You can create your own locale using the [defineLocale](https://ui.nuxt.com/docs/composables/define-locale) utility: ```vue [App.vue] ``` \> \[!TIP] \> Look at the \`code\` parameter, there you need to pass the iso code of the language. Example:\`hi\` Hindi (language)\`de-AT\`: German (language) as used in Austria (region) ### Extend locale You can customize an existing locale by overriding its `messages` or `code` using the [extendLocale](https://ui.nuxt.com/docs/composables/extend-locale) utility: ```vue [App.vue] ``` ### Dynamic locale To dynamically switch between languages, you can use the [Vue I18n](https://vue-i18n.intlify.dev/){rel=""nofollow""} plugin. Install the Vue I18n package \`\`\`bash pnpm add vue-i18n\@11 \`\`\` \`\`\`bash yarn add vue-i18n\@11 \`\`\` \`\`\`bash npm install vue-i18n\@11 \`\`\` \`\`\`bash bun add vue-i18n\@11 \`\`\` Use the Vue I18n plugin in your main.ts \`\`\`ts import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import { createI18n } from 'vue-i18n' import ui from '@nuxt/ui/vue-plugin' import App from './App.vue' const app = createApp(App) const router = createRouter({ routes: \[], history: createWebHistory() }) const i18n = createI18n({ legacy: false, locale: 'en', availableLocales: \['en', 'de'], messages: { en: { // ... }, de: { // ... } } }) app.use(router) app.use(i18n) app.use(ui) app.mount('#app') \`\`\` Set the locale prop using useI18n \`\`\`vue \ \ \`\`\` ### Dynamic direction Each locale has a `dir` property which will be used by the `App` component to set the directionality of all components. In a multilingual application, you might want to set the `lang` and `dir` attributes on the `` element dynamically based on the user's locale, which you can do with the [useHead](https://unhead.unjs.io/usage/composables/use-head){rel=""nofollow""} composable: ```vue [App.vue] ``` ## Supported languages \*See the full list of supported languages on the documentation website.\* # Content ## Installation To get started, you can follow the official [guide](https://content.nuxt.com/docs/getting-started/installation){rel=""nofollow""} or in summary: \`\`\`bash pnpm add @nuxt/content \`\`\` \`\`\`bash yarn add @nuxt/content \`\`\` \`\`\`bash npm install @nuxt/content \`\`\` \`\`\`bash bun add @nuxt/content \`\`\` Then, add the `@nuxt/content` module in your `nuxt.config.ts`: ```ts [nuxt.config.ts] {4} export default defineNuxtConfig({ modules: [ '@nuxt/ui', '@nuxt/content' ], css: ['~/assets/css/main.css'] }) ``` \> \[!CAUTION] \> You need to register \`@nuxt/content\` after \`@nuxt/ui\` in the \`modules\` array, otherwise the prose components will not be available. ## Configuration When using Tailwind CSS classes in your markdown content files, you need to ensure Tailwind can detect and generate the necessary utility classes. By default, Tailwind's automatic content detection might not pick up classes written in markdown files. To fix this, use the [`@source` directive](https://tailwindcss.com/docs/functions-and-directives#source-directive){rel=""nofollow""} in your CSS file to explicitly include your content directory: ```css [app/assets/css/main.css] @import "tailwindcss"; @import "@nuxt/ui"; @source "../../../content/**/*"; ``` This ensures that: - Tailwind scans all markdown files in your content directory - Any utility classes used in your markdown (like `text-primary`) are included in the final CSS - Dynamic classes in MDC components or custom Vue components within your content work properly \> \[!TIP] \> You can also use glob patterns to be more specific about which files to scan:\`@source "../../../content/docs/\*\*/\*.md"\` - Only scan markdown in the docs folder\`@source "../../../content/\*\*/\*.{md,yml}"\` - Include both markdown and YAML files \> \[!NOTE] \> See: https\://tailwindcss.com/docs/detecting-classes-in-source-files \> Learn more about Tailwind's automatic content detection and best practices for optimizing build performance. ## Components You might be using `@nuxt/content` to build a documentation. To help you with that, we've built some components that you can use in your pages: - a built-in full-text search command palette with [ContentSearch](https://ui.nuxt.com/docs/components/content-search), replacing the need for Algolia DocSearch - a navigation tree with the [ContentNavigation](https://ui.nuxt.com/docs/components/content-navigation) component - a sticky Table of Contents with the [ContentToc](https://ui.nuxt.com/docs/components/content-toc) component - a prev / next navigation with the [ContentSurround](https://ui.nuxt.com/docs/components/content-surround) component ## Typography Nuxt UI provides its own custom implementations of all prose components for seamless integration with `@nuxt/content`. This approach ensures consistent styling, complete control over typography, and perfect alignment with the Nuxt UI design system so your content always looks and feels cohesive out of the box. \> \[!NOTE] \> See: /docs/typography \> Discover the full Typography system and explore all available prose components for rich, consistent content presentation. ## Utils ### `mapContentNavigation` This util will map the navigation from `queryCollectionNavigation` and transform it recursively into an array of objects that can be used by various components. `mapContentNavigation(navigation, options?)` - `navigation`: The navigation tree (array of ContentNavigationItem). - `options`(optional): - `labelAttribute`: (string) Which field to use as label (`title` by default) - `deep`: (number or undefined) Controls how many levels of navigation are included (`undefined` by default : includes all levels) **Example:** As shown in the breadcrumb example below, it's commonly used to transform the navigation data into the correct format. ```vue [app.vue] ``` # SSR ## Usage When using Nuxt UI with Nuxt framework, SSR server will fully work out of the box. However, when using it with pure Vue, you will need to pay attention to some details to make it function as expected. ### Color Variables Injection Nuxt UI, by default, injects to the `` of the document color variables that are used across all components. Since the document is not managed by the UI library in the Vue SSR, you will need to inject that manually. You can do that by using `@unhead` in the following way: \`\`\`ts import { createHead, renderSSRHead } from '@unhead/vue/server' // Create the header with unhead const head = createHead() // Render SSR header and append it to the SSR application instance const payload = await renderSSRHead(head) app.head.push(payload.headTags) \`\`\` \`\`\`ts import { createInertiaApp } from '@inertiajs/vue3' import createServer from '@inertiajs/vue3/server' import ui from '@nuxt/ui/vue-plugin' import { createHead, renderSSRHead } from '@unhead/vue/server' import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers' import { createSSRApp, h } from 'vue' import { renderToString } from 'vue/server-renderer' import type { DefineComponent } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'Laravel x Nuxt UI' createServer( (page) => { const head = createHead() return createInertiaApp({ page, render: renderToString, title: (title) => (title ? \`${title} - ${appName}\` : appName), resolve: (name) => resolvePageComponent( \`./pages/${name}.vue\`, import.meta.glob\('./pages/\*\*/\*.vue') ), setup: ({ App, props, plugin }) => createSSRApp({ render: () => h(App, props) }) .use(plugin) .use(head) .use(ui) }).then(async (app) => { const payload = await renderSSRHead(head) app.head.push(payload.headTags) return app }) }, { cluster: true } ) \`\`\` \`\`\`ts import { createInertiaApp } from '@inertiajs/vue3' import createServer from '@inertiajs/vue3/server' import ui from '@nuxt/ui/vue-plugin' import { createHead, renderSSRHead } from '@unhead/vue/server' import { resolvePageComponent } from '@adonisjs/inertia/helpers' import { createSSRApp, h } from 'vue' import { renderToString } from 'vue/server-renderer' import type { DefineComponent } from 'vue' const appName = import.meta.env.VITE\_APP\_NAME || 'AdonisJS x Nuxt UI' createServer( (page) => { const head = createHead() return createInertiaApp({ page, render: renderToString, title: (title) => (title ? \`${title} - ${appName}\` : appName), resolve: (name) => resolvePageComponent( \`../pages/${name}.vue\`, import.meta.glob\('../pages/\*\*/\*.vue') ), setup: ({ App, props, plugin }) => createSSRApp({ render: () => h(App, props) }) .use(plugin) .use(head) .use(ui) }).then(async (app) => { const payload = await renderSSRHead(head) app.head.push(payload.headTags) return app }) }, { cluster: true } ) \`\`\` ### Color Scheme Detection The same goes to the color scheme detection. To avoid flashings in the SSR because of the selected color scheme difference, you will need to detect the user's color scheme before the application initialization. Adding the script below to the `` of your document will detect if the user is using dark theme, and therefore, render the SSR in the dark theme as well. \`\`\`html \ \`\`\` \`\`\`html \ \ \ \ \ @inertiaHead @vite('resources/js/app.ts') \ \ \ \
@inertia \
\ \ \`\`\` \`\`\`html \ \ \ \ \ @inertiaHead() @vite(\['inertia/app/app.ts', \`inertia/pages/${page.component}.vue\`]) \ \ \ @inertia({ class: 'isolate' }) \ \ \`\`\` ### Icons Display Unfortunately displaying icons with the SSR server of the Vue version is currently not supported. The icons will only be displayed after the application is initialized at the user's end. # MCP Server ## What is MCP? MCP (Model Context Protocol) is a standardized protocol that enables AI assistants to access external data sources and tools. Nuxt UI provides an MCP server that allows AI assistants like Claude Code, Cursor, and Windsurf to access component information, source code, and usage examples directly. The MCP server provides structured access to our component library, making it easy for AI tools to understand and assist with Nuxt UI development. ## Available Resources The Nuxt UI MCP server provides the following resources for discovery: - **`resource://nuxt-ui/components`**: Browse all available components with categories - **`resource://nuxt-ui/composables`**: Browse all available composables with categories - **`resource://nuxt-ui/examples`**: Browse all available code examples - **`resource://nuxt-ui/templates`**: Browse all available project templates - **`resource://nuxt-ui/documentation-pages`**: Browse all available documentation pages You're able to access these resources with tools like Claude Code by using `@`. ## Available Tools The Nuxt UI MCP server provides the following tools organized by category: ### Component Tools - **`list_components`**: Lists all available Nuxt UI components with their categories and basic information - **`list_composables`**: Lists all available Nuxt UI composables with their categories and basic information - **`get_component`**: Retrieves component documentation and details. Supports a `sections` parameter (`usage`, `examples`, `api`, `theme`, `changelog`) to fetch only specific parts and reduce response size - **`get_component_metadata`**: Retrieves detailed metadata for a component including props, slots, and events (lightweight, no documentation content) - **`search_components_by_category`**: Searches components by category or text filter ### Template Tools - **`list_templates`**: Lists all available Nuxt UI templates with optional category filtering - **`get_template`**: Retrieves template details and setup instructions ### Documentation Tools - **`list_documentation_pages`**: Lists all documentation pages - **`get_documentation_page`**: Retrieves documentation page content by URL path. Supports a `sections` parameter to fetch only specific h2 sections (e.g., `["Usage", "API"]`) and reduce response size - **`list_getting_started_guides`**: Lists all getting started guides and installation instructions ### Example Tools - **`list_examples`**: Lists all available UI examples and code demonstrations - **`get_example`**: Retrieves specific UI example implementation code and details ### Migration Tools - **`get_migration_guide`**: Retrieves version-specific migration guides and upgrade instructions ## Available Prompts The Nuxt UI MCP server provides guided prompts for common workflows: - **`find_component_for_usecase`**: Find the best component for your specific use case - **`implement_component_with_props`**: Generate complete component implementation with proper props - **`setup_project_with_template`**: Get guided setup instructions for project templates You're able to access these resources with tools like Claude Code by using `/`. ## Configuration The Nuxt UI MCP server uses HTTP transport and can be configured in different AI assistants. ### ChatGPT \> \[!NOTE] \> Custom connectors using MCP are available on ChatGPT for Pro and Plus accounts. Accessible on the web. Follow these steps to set up Nuxt UI as a connector within ChatGPT: 1. **Enable Developer mode:** - Go to "Settings" > "Connectors" > "Advanced settings" > "Developer mode" 2. **Open ChatGPT settings** 3. **In the Connectors tab, create a new connector:** - Give it a name: `Nuxt UI` - MCP server URL: `https://ui.nuxt.com/mcp` - Authentication: `None` 4. **Click Create** The Nuxt UI connector will appear in the composer's "Developer mode" tool later during conversations. ### Claude Code \> \[!NOTE] \> Ensure Claude Code is installed. Visit \[Anthropic's documentation]\(https\://docs.anthropic.com/en/docs/claude-code/quickstart) for installation instructions. Add the server using the CLI command: ```bash claude mcp add --transport http nuxt-ui-remote https://ui.nuxt.com/mcp ``` ### Claude Desktop #### Setup Instructions: 1. Open Claude Desktop and navigate to "Settings" > "Developer". 2. Click on "Edit Config". This will open the local Claude directory. 3. Modify the `claude_desktop_config.json` file with your custom MCP server configuration. ```json [claude_desktop_config.json] { "mcpServers": { "nuxt-ui": { "command": "npx", "args": [ "mcp-remote", "https://ui.nuxt.com/mcp" ] } } } ``` 4. Restart Claude Desktop app. The Nuxt UI MCP server should now be registered. ### Cursor #### Quick Install Click the button below to install the Nuxt UI MCP server directly in Cursor: \[Install MCP Server]\(cursor://anysphere.cursor-deeplink/mcp/install?name=nuxt-ui\&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vdWkubnV4dC5jb20vbWNwIn0%3D) #### Manual Setup Instructions: 1. Open Cursor and go to "Settings" > "Tools & MCP" 2. Add the Nuxt UI MCP server configuration Or manually create/update `.cursor/mcp.json` in your project root: ```json [.cursor/mcp.json] { "mcpServers": { "nuxt-ui": { "type": "http", "url": "https://ui.nuxt.com/mcp" } } } ``` ### Google Antigravity #### Setup Instructions: 1. Open the MCP store via the "..." dropdown at the top of the editor's agent panel. 2. Click on "Manage MCP Servers" 3. Click on "View raw config" 4. Modify the `mcp_config.json` with your custom MCP server configuration: ```json { "mcpServers": { "nuxt-ui": { "serverUrl": "https://ui.nuxt.com/mcp" } } } ``` 5. Return to the "Manage MCP Servers" tab and click "Refresh". The Nuxt UI MCP server should now appear. ### Gemini CLI #### Setup Instructions: 1. Locate your Gemini CLI configuration file (usually \~/.gemini/settings.json or as specified in your environment). 2. Add the following configuration to your mcpServers object: ```json { "mcpServers": { "nuxt-ui": { "url": "https://ui.nuxt.com/mcp" } } } ``` 3. Restart your terminal session or reload the CLI. The Nuxt UI MCP server tools will now be available for use. ### Le Chat Mistral #### Setup Instructions: 1. Navigate to "Intelligence" > "Connectors" 2. Click on "Add Connector" button, then select "Custom MCP Connector" 3. Create your Custom MCP Connector: - Connector Name: `NuxtUI` - Connector Server: `https://ui.nuxt.com/mcp` ### Visual Studio Code \> \[!NOTE] \> Install required extensions. Ensure you have \[GitHub Copilot]\(https\://marketplace.visualstudio.com/items?itemName=GitHub.copilot) and \[GitHub Copilot Chat]\(https\://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat) extensions installed. #### Setup Instructions: 1. Open VS Code and access the Command Palette (Ctrl/Cmd + Shift + P) 2. Type "Preferences: Open Workspace Settings (JSON)" and select it 3. Navigate to your project's `.vscode` folder or create one if it doesn't exist 4. Create or edit the `mcp.json` file with the following configuration: ```json [.vscode/mcp.json] { "servers": { "nuxt-ui": { "type": "http", "url": "https://ui.nuxt.com/mcp" } } } ``` ### Windsurf #### Setup Instructions: 1. Open Windsurf and navigate to "Settings" > "Windsurf Settings" > "Cascade" 2. Click the "Manage MCPs" button, then select the "View raw config" option 3. Add the following configuration to your MCP settings: ```json [.codeium/windsurf/mcp_config.json] { "mcpServers": { "nuxt-ui": { "type": "http", "url": "https://ui.nuxt.com/mcp" } } } ``` ### Zed #### Setup Instructions: 1. Open Zed and go to "Settings" > "Open Settings" 2. Navigate to the JSON settings file 3. Add the following context server configuration to your settings: ```json [.config/zed/settings.json] { "context_servers": { "nuxt-ui": { "source": "custom", "command": "npx", "args": ["mcp-remote", "https://ui.nuxt.com/mcp"], "env": {} } } } ``` ### Opencode #### Setup Instructions: 1. In your project root, create `opencode.json` 2. Add the following configuration: ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "nuxt-ui": { "type": "remote", "url": "https://ui.nuxt.com/mcp", "enabled": true } } } ``` ### GitHub Copilot Agent \> \[!NOTE] \> Repository administrator access required. This is needed to configure MCP servers for GitHub Copilot coding agent. If you have already configured MCP servers in VS Code (replace the `servers` key with `mcpServers` for GitHub Copilot Agent), you can leverage a similar configuration for GitHub Copilot coding agent. You will need to add a `tools` key specifying which tools are available to Copilot. #### Setup Instructions: 1. Navigate to your GitHub repository 2. Go to **Settings** > **Code & automation** > **Copilot** > **Coding agent** 3. In the **MCP configuration** section, add the following configuration: ```json { "mcpServers": { "nuxt-ui": { "type": "http", "url": "https://ui.nuxt.com/mcp", "tools": ["*"] } } } ``` 4. Click Save ### Validating the Configuration To verify the MCP server is configured correctly: 1. Create an issue in your repository and assign it to Copilot 2. Wait for Copilot to create a pull request 3. In the pull request, click View session in the "Copilot started work" timeline event 4. Click the ellipsis button (...) at the top right, then click Copilot in the sidebar 5. Expand the Start MCP Servers step to see the configured Nuxt tools For more information on using MCP with GitHub Copilot coding agent, see [Extend coding agent with MCP](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/extend-coding-agent-with-mcp){rel=""nofollow""}. ## Usage Examples Once configured, you can ask your AI assistant questions like: - "List all available Nuxt UI components" - "Get Button component documentation" - "Show me just the Button usage examples" - "What props does Input accept?" - "Find form-related components" - "List dashboard templates" - "Get template setup instructions" - "Show installation guide" - "Get v4 migration guide" - "List all examples" - "Get ContactForm example code" The AI assistant will use the MCP server to fetch structured JSON data and provide guided assistance for Nuxt UI during development. \> \[!TIP] \> For large documentation pages, the AI can use the \`sections\` parameter to fetch only relevant parts (like "Usage" or "API"), reducing response size and improving performance. # LLMs.txt ## What is LLMs.txt? LLMs.txt is a structured documentation format specifically designed for large language models (LLMs). Nuxt UI provides LLMs.txt files that contain comprehensive information about our component library, making it easy for AI tools to understand and assist with Nuxt UI development. These files are optimized for AI consumption and contain structured information about components, APIs, usage patterns, and best practices. ## Available routes We provide LLMs.txt routes to help AI tools access our documentation: - **`/llms.txt`** - Contains a structured overview of all components and their documentation links (\~5K tokens) - **`/llms-full.txt`** - Provides comprehensive documentation including implementation details, examples, theming, composables, and migration guidance (\~1M+ tokens) ## Choosing the Right File \> \[!NOTE] \> Most users should start with \`/llms.txt\` - it contains all essential information and works with standard LLM context windows. Use \`/llms-full.txt\` only if you need comprehensive implementation examples and your AI tool supports large contexts (200K+ tokens). ## Important usage notes \> \[!WARNING] \> @-symbol must be typed manually - When using tools like Cursor or Windsurf, the \`@\` symbol must be typed by hand in the chat interface. Copy-pasting breaks the tool's ability to recognize it as a context reference. ## Usage with AI Tools ### Cursor Nuxt UI provides specialized LLMs.txt files that you can reference in Cursor for better AI assistance with component development. #### How to use: 1. **Direct reference**: Mention the LLMs.txt URLs when asking questions 2. Add these specific URLs to your project context using `@docs` [Read more about Cursor Web and Docs Search](https://docs.cursor.com/en/context/@-symbols/@-docs){rel=""nofollow""} ### Windsurf Windsurf can directly access the Nuxt UI LLMs.txt files to understand component usage and best practices. #### Using LLMs.txt with Windsurf: - Use `@docs` to reference specific LLMs.txt URLs - Create persistent rules referencing these URLs in your workspace [Read more about Windsurf Web and Docs Search](https://docs.windsurf.com/windsurf/cascade/web-search){rel=""nofollow""} ### Other AI Tools Any AI tool that supports LLMs.txt can use these routes to better understand Nuxt UI. #### Examples for ChatGPT, Claude, or other LLMs: - "Using Nuxt UI documentation from {rel=""nofollow""}" - "Follow complete Nuxt UI guidelines from {rel=""nofollow""}" # Skills ## What are Skills? Skills are structured knowledge files that give AI coding agents context about a library, framework, or codebase. Unlike MCP servers that provide real-time tool access, skills are loaded directly into the agent's context so it can reference them throughout the conversation. Nuxt UI provides two skills: - **Usage skill** — Teaches AI agents how to build UIs with Nuxt UI: installation, theming, components, composables, forms, overlays, and layouts. - **Contributing skill** — Guides AI agents through Nuxt UI's component structure, theming patterns, testing conventions, and documentation guidelines when contributing to the repository. ## Usage Skill The usage skill gives AI agents comprehensive knowledge about building with Nuxt UI v4. It covers: - Installation for Nuxt, Vue, Laravel, and AdonisJS - Theming and branding with semantic colors and CSS variables - All 125+ components with props and usage patterns - Composables (`useToast`, `useOverlay`, `defineShortcuts`) - Form validation with Standard Schema - Layout composition (Dashboard, Docs, Chat, Editor) - Official starter templates The skill includes additional references that the AI agent loads on demand based on the task, keeping responses focused and context-efficient. \> \[!NOTE] \> Once installed, you can invoke the skill by typing \`/nuxt-ui\` in your agent's chat. ### Skills CLI The [`skills`](https://skills.sh){rel=""nofollow""} CLI is the easiest way to install the Nuxt UI skill. It supports 35+ agents including Cursor, Claude Code, Codex, Windsurf, Cline, and more. ```bash npx skills add nuxt/ui ``` You can target specific agents with the `--agent` flag: ```bash npx skills add nuxt/ui --agent cursor npx skills add nuxt/ui --agent claude-code ``` Or install globally so the skill is available across all your projects: ```bash npx skills add nuxt/ui --global ``` \> \[!TIP] \> Visit \[skills.sh]\(https\://skills.sh) to learn more about the skills ecosystem and browse available skills. ### Cursor #### Quick Install Click the button below to install the Nuxt UI skill directly in Cursor: \[Install Skill]\(cursor://anysphere.cursor-deeplink/install-skill?url=https\://github.com/nuxt/ui/tree/v4/skills/nuxt-ui) #### Manual Setup 1. Open Cursor and go to "Settings" > "Skills" 2. Click "Add skill" and enter the following URL: ```text https://github.com/nuxt/ui/tree/v4/skills/nuxt-ui ``` ### Claude Code \> \[!NOTE] \> Ensure Claude Code is installed. Visit \[Anthropic's documentation]\(https\://docs.anthropic.com/en/docs/claude-code/quickstart) for installation instructions. Add the skill using the CLI command: ```bash claude skill add https://github.com/nuxt/ui/tree/v4/skills/nuxt-ui ``` ### Other AI Tools The skill files are publicly available on GitHub. You can reference them directly in any AI tool that supports custom context or instructions: - **Skill entry point**: [`skills/nuxt-ui/SKILL.md`](https://github.com/nuxt/ui/tree/v4/skills/nuxt-ui/SKILL.md){rel=""nofollow""} - **Full skill directory**: [`skills/nuxt-ui/`](https://github.com/nuxt/ui/tree/v4/skills/nuxt-ui){rel=""nofollow""} ## Contributing Skill The contributing skill helps AI agents assist with contributions to the Nuxt UI repository. It automatically guides through: - Component file structure and naming conventions - Tailwind Variants theming patterns - Vitest testing conventions - MDC documentation guidelines This skill is located in the repository at [`.claude/skills/contributing/`](https://github.com/nuxt/ui/tree/v4/.claude/skills/contributing){rel=""nofollow""} and is automatically picked up when working in the Nuxt UI codebase with Claude Code or Cursor (when using a Claude model). You can also invoke it by typing `/contributing` in your agent's chat. \> \[!TIP] \> For more details on contributing to Nuxt UI, see the \[Contribution guide]\(/docs/getting-started/contribution#ai-assistance). # Accordion ## Usage Use the Accordion component to display a list of collapsible items. ```vue ``` ### Items Use the `items` prop as an array of objects with the following properties: - `label?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `icon?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `trailingIcon?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `content?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `value?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `disabled?: boolean`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - [`slot?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"}](https://ui.nuxt.com/#with-custom-slot) - `class?: any`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `ui?: { item?: ClassNameValue, header?: ClassNameValue, trigger?: ClassNameValue, leadingIcon?: ClassNameValue, label?: ClassNameValue, trailingIcon?: ClassNameValue, content?: ClassNameValue, body?: ClassNameValue }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```vue ``` ### Multiple Set the `type` prop to `multiple` to allow multiple items to be active at the same time. Defaults to `single`. ```vue ``` ### Collapsible When `type` is `single`, you can set the `collapsible` prop to `false` to prevent the active item from collapsing. ```vue ``` ### Unmount Use the `unmount-on-hide` prop to prevent the content from being unmounted when the accordion is collapsed. Defaults to `true`. ```vue ``` \> \[!NOTE] \> You can inspect the DOM to see each item's content being rendered. ### Disabled Use the `disabled` property to disable the Accordion. You can also disable a specific item by using the `disabled` property in the item object. ```vue ``` ### Trailing Icon Use the `trailing-icon` prop to customize the trailing [Icon](https://ui.nuxt.com/docs/components/icon) of each item. Defaults to `i-lucide-chevron-down`. \> \[!TIP] \> You can also set an icon for a specific item by using the \`trailingIcon\` property in the item object. ```vue ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/nuxt#theme \> You can customize this icon globally in your \`app.config.ts\` under \`ui.icons.chevronDown\` key. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/vue#theme \> You can customize this icon globally in your \`vite.config.ts\` under \`ui.icons.chevronDown\` key. ## Examples ### Control active item(s) You can control the active item by using the `default-value` prop or the `v-model` directive with the `value` of the item. If no `value` is provided, it defaults to the index **as a string**. ```vue [AccordionModelValueExample.vue] ``` \> \[!TIP] \> Use the \`value-key\` prop to change the key used to match items when a \`v-model\` or \`default-value\` is provided. \> \[!CAUTION] \> When \`type="multiple"\`, ensure to pass an array to the \`default-value\` prop or the \`v-model\` directive. ### With drag and drop Use the [`useSortable`](https://vueuse.org/integrations/useSortable/){rel=""nofollow""} composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html){rel=""nofollow""} to enable drag and drop functionality on the Accordion. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/){rel=""nofollow""} to provide a seamless drag and drop experience. ```vue [AccordionDragAndDropExample.vue] ``` ### With body slot Use the `#body` slot to customize the body of each item. ```vue [AccordionBodySlotExample.vue] ``` \> \[!TIP] \> The \`#body\` slot includes some pre-defined styles, use the \[\`#content\` slot]\(#with-content-slot) if you want to start from scratch. ### With content slot Use the `#content` slot to customize the content of each item. ```vue [AccordionContentSlotExample.vue] ``` ### With custom slot Use the `slot` property to customize a specific item. You will have access to the following slots: - `#{{ item.slot }}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `#{{ item.slot }}-body`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```vue [AccordionCustomSlotExample.vue] ``` ### With markdown content You can use the [MDC](https://github.com/nuxt-modules/mdc?tab=readme-ov-file#mdc){rel=""nofollow""} component from `@nuxtjs/mdc` to render markdown in the accordion items. ```vue [AccordionMarkdownExample.vue] ``` ## API ### Props ```ts /** * Props for the Accordion component */ interface AccordionProps { /** * The element or component this component should render as. */ as?: any; items?: T[] | undefined; /** * The icon displayed on the right side of the trigger. */ trailingIcon?: any; /** * The key used to get the value from the item. * @default "\"value\"" */ valueKey?: GetItemKeys | undefined; /** * The key used to get the label from the item. * @default "\"label\"" */ labelKey?: GetItemKeys | undefined; ui?: { root?: ClassNameValue; item?: ClassNameValue; header?: ClassNameValue; trigger?: ClassNameValue; content?: ClassNameValue; body?: ClassNameValue; leadingIcon?: ClassNameValue; trailingIcon?: ClassNameValue; label?: ClassNameValue; } | undefined; /** * When type is "single", allows closing content when clicking trigger for an open item. * When type is "multiple", this prop has no effect. * @default "true" */ collapsible?: boolean | undefined; /** * The default active value of the item(s). * * Use when you do not need to control the state of the item(s). */ defaultValue?: string | string[] | undefined; /** * The controlled value of the active item(s). * * Use this when you need to control the state of the items. Can be binded with `v-model` */ modelValue?: string | string[] | undefined; /** * Determines whether a "single" or "multiple" items can be selected at a time. * * This prop will overwrite the inferred type from `modelValue` and `defaultValue`. * @default "\"single\"" */ type?: SingleOrMultipleType | undefined; /** * When `true`, prevents the user from interacting with the accordion and all its items */ disabled?: boolean | undefined; /** * When `true`, the element will be unmounted on closed state. * @default "true" */ unmountOnHide?: boolean | undefined; } ``` ### Slots ```ts /** * Slots for the Accordion component */ interface AccordionSlots { default(): any; leading(): any; trailing(): any; content(): any; body(): any; } ``` ### Emits ```ts /** * Emitted events for the Accordion component */ interface AccordionEmits { update:modelValue: (payload: [value: string | string[] | undefined]) => void; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { accordion: { slots: { root: 'w-full', item: 'border-b border-default last:border-b-0', header: 'flex', trigger: 'group flex-1 flex items-center gap-1.5 font-medium text-sm py-3.5 focus-visible:outline-primary min-w-0', content: 'data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none', body: 'text-sm pb-3.5', leadingIcon: 'shrink-0 size-5', trailingIcon: 'shrink-0 size-5 ms-auto group-data-[state=open]:rotate-180 transition-transform duration-200', label: 'text-start break-words' }, variants: { disabled: { true: { trigger: 'cursor-not-allowed opacity-75' } } } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Accordion.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/accordion.ts). # Alert ## Usage ### Title Use the `title` prop to set the title of the Alert. ```vue ``` ### Description Use the `description` prop to set the description of the Alert. ```vue ``` ### Icon Use the `icon` prop to show an [Icon](https://ui.nuxt.com/docs/components/icon). ```vue ``` ### Avatar Use the `avatar` prop to show an [Avatar](https://ui.nuxt.com/docs/components/avatar). ```vue ``` ### Color Use the `color` prop to change the color of the Alert. ```vue ``` ### Variant Use the `variant` prop to change the variant of the Alert. ```vue ``` ### Close Use the `close` prop to display a [Button](https://ui.nuxt.com/docs/components/button) to dismiss the Alert. \> \[!TIP] \> An \`update\:open\` event will be emitted when the close button is clicked. ```vue ``` You can pass any property from the [Button](https://ui.nuxt.com/docs/components/button) component to customize it. ```vue ``` ### Close Icon Use the `close-icon` prop to customize the close button [Icon](https://ui.nuxt.com/docs/components/icon). Defaults to `i-lucide-x`. ```vue ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/nuxt#theme \> You can customize this icon globally in your \`app.config.ts\` under \`ui.icons.close\` key. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/vue#theme \> You can customize this icon globally in your \`vite.config.ts\` under \`ui.icons.close\` key. ### Actions Use the `actions` prop to add some [Button](https://ui.nuxt.com/docs/components/button) actions to the Alert. ```vue ``` ### Orientation Use the `orientation` prop to change the orientation of the Alert. ```vue ``` ## Examples ### `class` prop Use the `class` prop to override the base styles of the Alert. ```vue ``` ### `ui` prop Use the `ui` prop to override the slots styles of the Alert. ```vue ``` ## API ### Props ```ts /** * Props for the Alert component */ interface AlertProps { /** * The element or component this component should render as. */ as?: any; title?: string | undefined; description?: string | undefined; icon?: any; avatar?: AvatarProps | undefined; color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; variant?: "solid" | "outline" | "soft" | "subtle" | undefined; /** * The orientation between the content and the actions. * @default "\"vertical\"" */ orientation?: "vertical" | "horizontal" | undefined; /** * Display a list of actions: * - under the title and description when orientation is `vertical` * - next to the close button when orientation is `horizontal` * `{ size: 'xs' }`{lang="ts-type"} */ actions?: ButtonProps[] | undefined; /** * Display a close button to dismiss the alert. * `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"} */ close?: boolean | Omit | undefined; /** * The icon displayed in the close button. */ closeIcon?: any; ui?: { root?: ClassNameValue; wrapper?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; icon?: ClassNameValue; avatar?: ClassNameValue; avatarSize?: ClassNameValue; actions?: ClassNameValue; close?: ClassNameValue; } | undefined; } ``` ### Slots ```ts /** * Slots for the Alert component */ interface AlertSlots { leading(): any; title(): any; description(): any; actions(): any; close(): any; } ``` ### Emits ```ts /** * Emitted events for the Alert component */ interface AlertEmits { update:open: (payload: [value: boolean]) => void; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { alert: { slots: { root: 'relative overflow-hidden w-full rounded-lg p-4 flex gap-2.5', wrapper: 'min-w-0 flex-1 flex flex-col', title: 'text-sm font-medium', description: 'text-sm opacity-90', icon: 'shrink-0 size-5', avatar: 'shrink-0', avatarSize: '2xl', actions: 'flex flex-wrap gap-1.5 shrink-0', close: 'p-0' }, variants: { color: { primary: '', secondary: '', success: '', info: '', warning: '', error: '', neutral: '' }, variant: { solid: '', outline: '', soft: '', subtle: '' }, orientation: { horizontal: { root: 'items-center', actions: 'items-center' }, vertical: { root: 'items-start', actions: 'items-start mt-2.5' } }, title: { true: { description: 'mt-1' } } }, compoundVariants: [ { color: 'primary', variant: 'solid', class: { root: 'bg-primary text-inverted' } }, { color: 'secondary', variant: 'solid', class: { root: 'bg-secondary text-inverted' } }, { color: 'success', variant: 'solid', class: { root: 'bg-success text-inverted' } }, { color: 'info', variant: 'solid', class: { root: 'bg-info text-inverted' } }, { color: 'warning', variant: 'solid', class: { root: 'bg-warning text-inverted' } }, { color: 'error', variant: 'solid', class: { root: 'bg-error text-inverted' } }, { color: 'primary', variant: 'outline', class: { root: 'text-primary ring ring-inset ring-primary/25' } }, { color: 'secondary', variant: 'outline', class: { root: 'text-secondary ring ring-inset ring-secondary/25' } }, { color: 'success', variant: 'outline', class: { root: 'text-success ring ring-inset ring-success/25' } }, { color: 'info', variant: 'outline', class: { root: 'text-info ring ring-inset ring-info/25' } }, { color: 'warning', variant: 'outline', class: { root: 'text-warning ring ring-inset ring-warning/25' } }, { color: 'error', variant: 'outline', class: { root: 'text-error ring ring-inset ring-error/25' } }, { color: 'primary', variant: 'soft', class: { root: 'bg-primary/10 text-primary' } }, { color: 'secondary', variant: 'soft', class: { root: 'bg-secondary/10 text-secondary' } }, { color: 'success', variant: 'soft', class: { root: 'bg-success/10 text-success' } }, { color: 'info', variant: 'soft', class: { root: 'bg-info/10 text-info' } }, { color: 'warning', variant: 'soft', class: { root: 'bg-warning/10 text-warning' } }, { color: 'error', variant: 'soft', class: { root: 'bg-error/10 text-error' } }, { color: 'primary', variant: 'subtle', class: { root: 'bg-primary/10 text-primary ring ring-inset ring-primary/25' } }, { color: 'secondary', variant: 'subtle', class: { root: 'bg-secondary/10 text-secondary ring ring-inset ring-secondary/25' } }, { color: 'success', variant: 'subtle', class: { root: 'bg-success/10 text-success ring ring-inset ring-success/25' } }, { color: 'info', variant: 'subtle', class: { root: 'bg-info/10 text-info ring ring-inset ring-info/25' } }, { color: 'warning', variant: 'subtle', class: { root: 'bg-warning/10 text-warning ring ring-inset ring-warning/25' } }, { color: 'error', variant: 'subtle', class: { root: 'bg-error/10 text-error ring ring-inset ring-error/25' } }, { color: 'neutral', variant: 'solid', class: { root: 'text-inverted bg-inverted' } }, { color: 'neutral', variant: 'outline', class: { root: 'text-highlighted bg-default ring ring-inset ring-default' } }, { color: 'neutral', variant: 'soft', class: { root: 'text-highlighted bg-elevated/50' } }, { color: 'neutral', variant: 'subtle', class: { root: 'text-highlighted bg-elevated/50 ring ring-inset ring-accented' } } ], defaultVariants: { color: 'primary', variant: 'solid' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Alert.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/alert.ts). # App ## Usage This component implements Reka UI [ConfigProvider](https://reka-ui.com/docs/utilities/config-provider){rel=""nofollow""} to provide global configuration to all components: - Enables all primitives to inherit global reading direction. - Enables changing the behavior of scroll body when setting body lock. - Much more controls to prevent layout shifts. It's also using [ToastProvider](https://reka-ui.com/docs/components/toast#provider){rel=""nofollow""} and [TooltipProvider](https://reka-ui.com/docs/components/tooltip#provider){rel=""nofollow""} to provide global toasts and tooltips, as well as programmatic modals and slideovers. Wrap your entire application with the App component in your `app.vue` file: ```vue [app.vue] ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/i18n/nuxt#locale \> Learn how to use the \`locale\` prop to change the locale of your app. This also controls the date/time format in components like Calendar, InputDate, and InputTime. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/i18n/vue#locale \> Learn how to use the \`locale\` prop to change the locale of your app. This also controls the date/time format in components like Calendar, InputDate, and InputTime. ## API ### Props ```ts /** * Props for the App component */ interface AppProps { tooltip?: TooltipProviderProps | undefined; toaster?: ToasterProps | null | undefined; locale?: Locale | undefined; /** * @default "\"body\"" */ portal?: string | boolean | HTMLElement | undefined; /** * The global reading direction of your application. This will be inherited by all primitives. */ dir?: Direction | undefined; /** * The global scroll body behavior of your application. This will be inherited by the related primitives. */ scrollBody?: boolean | ScrollBodyOption | undefined; /** * The global `nonce` value of your application. This will be inherited by the related primitives. */ nonce?: string | undefined; } ``` ### Slots ```ts /** * Slots for the App component */ interface AppSlots { default(): any; } ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/App.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/app.ts). # AuthForm ## Usage Built on top of the [Form](https://ui.nuxt.com/docs/components/form) component, the `AuthForm` component can be used in your pages or wrapped in a [PageCard](https://ui.nuxt.com/docs/components/page-card). ```vue [AuthFormExample.vue] ``` ### Fields The Form will construct itself based on the `fields` prop and the state will be handled internally. Use the `fields` prop as an array of objects with the following properties: - `name: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `type: 'checkbox' | 'select' | 'otp' | 'InputHTMLAttributes['type']'`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} Each field must include a `type` property, which determines the input component and any additional props applied: `checkbox` fields use [Checkbox](https://ui.nuxt.com/docs/components/checkbox#props) props, `select` fields use [SelectMenu](https://ui.nuxt.com/docs/components/select-menu#props) props, `otp` fields use [PinInput](https://ui.nuxt.com/docs/components/pin-input#props) props, and all other types use [Input](https://ui.nuxt.com/docs/components/input#props) props. You can also pass any property from the [FormField](https://ui.nuxt.com/docs/components/form-field#props) component to each field. ```vue ``` ### Title Use the `title` prop to set the title of the Form. ```vue ``` ### Description Use the `description` prop to set the description of the Form. ```vue ``` ### Icon Use the `icon` prop to set the icon of the Form. ```vue ``` ### Providers Use the `providers` prop to add providers to the form. You can pass any property from the [Button](https://ui.nuxt.com/docs/components/button) component such as `variant`, `color`, `to`, etc. ```vue ``` ### Separator Use the `separator` prop to customize the [Separator](https://ui.nuxt.com/docs/components/separator) between the providers and the fields. Defaults to `or`. ```vue ``` You can pass any property from the [Separator](https://ui.nuxt.com/docs/components/separator#props) component to customize it. ```vue ``` ### Submit Use the `submit` prop to change the submit button of the Form. You can pass any property from the [Button](https://ui.nuxt.com/docs/components/button) component such as `variant`, `color`, `to`, etc. ```vue ``` ## Examples ### Within a page You can wrap the `AuthForm` component with the [PageCard](https://ui.nuxt.com/docs/components/page-card) component to display it within a `login.vue` page for example. ```vue [AuthFormPageExample.vue] ``` ## API ### Props ```ts /** * Props for the AuthForm component */ interface AuthFormProps { /** * The element or component this component should render as. */ as?: any; /** * The icon displayed above the title. */ icon?: any; title?: string | undefined; description?: string | undefined; fields?: F[] | undefined; /** * Display a list of Button under the description. * `{ color: 'neutral', variant: 'subtle', block: true }`{lang="ts-type"} */ providers?: ButtonProps[] | undefined; /** * The text displayed in the separator. * @default "\"or\"" */ separator?: string | SeparatorProps | undefined; /** * Display a submit button at the bottom of the form. * `{ label: 'Continue', block: true }`{lang="ts-type"} */ submit?: Omit | undefined; schema?: T | undefined; validate?: ((state: Partial>) => FormError[] | Promise[]>) | undefined; validateOn?: FormInputEvents[] | undefined; validateOnInputDelay?: number | undefined; disabled?: boolean | undefined; loading?: boolean | undefined; loadingAuto?: boolean | undefined; ui?: { root?: ClassNameValue; header?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; body?: ClassNameValue; providers?: ClassNameValue; checkbox?: ClassNameValue; select?: ClassNameValue; password?: ClassNameValue; otp?: ClassNameValue; input?: ClassNameValue; separator?: ClassNameValue; form?: ClassNameValue; footer?: ClassNameValue; } | undefined; name?: string | undefined; autocomplete?: string | undefined; acceptcharset?: string | undefined; action?: string | undefined; enctype?: string | undefined; method?: string | undefined; novalidate?: Booleanish | undefined; target?: string | undefined; } ``` \> \[!NOTE] \> See: https\://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attributes \> This component also supports all native \`\
\` HTML attributes. ### Slots ```ts /** * Slots for the AuthForm component */ interface AuthFormSlots { header(): any; leading(): any; title(): any; description(): any; providers(): any; validation(): any; submit(): any; footer(): any; } ``` ### Emits ```ts /** * Emitted events for the AuthForm component */ interface AuthFormEmits { submit: (payload: [payload: FormSubmitEvent>>]) => void; } ``` ### Expose You can access the typed component instance (exposing formRef and state) using [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref){rel=""nofollow""}. For example, in a separate form (e.g. a "reset" form) you can do: ```vue ``` This gives you access to the following (exposed) properties: | Name | Type | | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `formRef`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | `Ref`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | | `state`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | `Reactive`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { authForm: { slots: { root: 'w-full space-y-6', header: 'flex flex-col text-center', leading: 'mb-2', leadingIcon: 'size-8 shrink-0 inline-block', title: 'text-xl text-pretty font-semibold text-highlighted', description: 'mt-1 text-base text-pretty text-muted', body: 'gap-y-6 flex flex-col', providers: 'space-y-3', checkbox: '', select: 'w-full', password: 'w-full', otp: 'w-full', input: 'w-full', separator: '', form: 'space-y-5', footer: 'text-sm text-center text-muted mt-2' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/AuthForm.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/auth-form.ts). # Avatar ## Usage The Avatar uses the `` component when [`@nuxt/image`](https://github.com/nuxt/image){rel=""nofollow""} is installed, falling back to `img` otherwise. ```vue ``` \> \[!NOTE] \> You can pass any property from the HTML \`\\` element such as \`alt\`, \`loading\`, etc. \> \[!TIP] \> To opt-out of \`@nuxt/image\`, use the \`as\` prop: \`:as="{ img: 'img' }"\`. ### Src Use the `src` prop to set the image URL. ```vue ``` ### Size Use the `size` prop to set the size of the Avatar. ```vue ``` \> \[!NOTE] \> The \`\\` element's \`width\` and \`height\` are automatically set based on the \`size\` prop. ### Icon Use the `icon` prop to display a fallback [Icon](https://ui.nuxt.com/docs/components/icon). ```vue ``` ### Text Use the `text` prop to display a fallback text. ```vue ``` ### Alt When no icon or text is provided, the **initials** of the `alt` prop is used as fallback. ```vue ``` \> \[!NOTE] \> The \`alt\` prop is passed to the \`img\` element as the \`alt\` attribute. ### Chip Use the `chip` prop to display a chip around the Avatar. ```vue ``` ## Examples ### With tooltip You can use a [Tooltip](https://ui.nuxt.com/docs/components/tooltip) component to display a tooltip when hovering the Avatar. ```vue [AvatarTooltipExample.vue] ``` ### With mask You can use a CSS mask to display an Avatar with a custom shape instead of a simple circle. ```vue [AvatarMaskExample.vue] ``` ## API ### Props ```ts /** * Props for the Avatar component */ interface AvatarProps { /** * The element or component this component should render as. */ as?: any; src?: string | undefined; alt?: string | undefined; icon?: any; text?: string | undefined; size?: "2xl" | "md" | "3xs" | "2xs" | "xs" | "sm" | "lg" | "xl" | "3xl" | undefined; chip?: boolean | ChipProps | undefined; ui?: { root?: ClassNameValue; image?: ClassNameValue; fallback?: ClassNameValue; icon?: ClassNameValue; } | undefined; loading?: "lazy" | "eager" | undefined; referrerpolicy?: HTMLAttributeReferrerPolicy | undefined; crossorigin?: "" | "anonymous" | "use-credentials" | undefined; decoding?: "async" | "auto" | "sync" | undefined; height?: Numberish | undefined; sizes?: string | undefined; srcset?: string | undefined; usemap?: string | undefined; width?: Numberish | undefined; } ``` \> \[!NOTE] \> See: https\://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes \> This component also supports all native \`\\` HTML attributes. ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { avatar: { slots: { root: 'inline-flex items-center justify-center shrink-0 select-none rounded-full align-middle bg-elevated', image: 'h-full w-full rounded-[inherit] object-cover', fallback: 'font-medium leading-none text-muted truncate', icon: 'text-muted shrink-0' }, variants: { size: { '3xs': { root: 'size-4 text-[8px]' }, '2xs': { root: 'size-5 text-[10px]' }, xs: { root: 'size-6 text-xs' }, sm: { root: 'size-7 text-sm' }, md: { root: 'size-8 text-base' }, lg: { root: 'size-9 text-lg' }, xl: { root: 'size-10 text-xl' }, '2xl': { root: 'size-11 text-[22px]' }, '3xl': { root: 'size-12 text-2xl' } } }, defaultVariants: { size: 'md' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Avatar.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/avatar.ts). # AvatarGroup ## Usage Wrap multiple [Avatar](https://ui.nuxt.com/docs/components/avatar) within an AvatarGroup to stack them. ```vue ``` ### Size Use the `size` prop to change the size of all the avatars. ```vue ``` ### Max Use the `max` prop to limit the number of avatars displayed. The rest is displayed as an `+X` avatar. ```vue ``` ## Examples ### With tooltip Wrap each avatar with a [Tooltip](https://ui.nuxt.com/docs/components/tooltip) to display a tooltip on hover. ```vue [AvatarGroupTooltipExample.vue] ``` ### With chip Wrap each avatar with a [Chip](https://ui.nuxt.com/docs/components/chip) to display a chip around the avatar. ```vue [AvatarGroupChipExample.vue] ``` ### With link Wrap each avatar with a [Link](https://ui.nuxt.com/docs/components/link) to make them clickable. ```vue [AvatarGroupLinkExample.vue] ``` ### With mask Wrap an avatar with a CSS mask to display it with a custom shape. ```vue [AvatarGroupMaskExample.vue] ``` \> \[!WARNING] \> The \`chip\` prop does not work correctly when using a mask. Chips may be cut depending on the mask shape. ## API ### Props ```ts /** * Props for the AvatarGroup component */ interface AvatarGroupProps { /** * The element or component this component should render as. */ as?: any; size?: "2xl" | "md" | "3xs" | "2xs" | "xs" | "sm" | "lg" | "xl" | "3xl" | undefined; /** * The maximum number of avatars to display. */ max?: string | number | undefined; ui?: { root?: ClassNameValue; base?: ClassNameValue; } | undefined; } ``` ### Slots ```ts /** * Slots for the AvatarGroup component */ interface AvatarGroupSlots { default(): any; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { avatarGroup: { slots: { root: 'inline-flex flex-row-reverse justify-end', base: 'relative rounded-full ring-bg first:me-0' }, variants: { size: { '3xs': { base: 'ring -me-0.5' }, '2xs': { base: 'ring -me-0.5' }, xs: { base: 'ring -me-0.5' }, sm: { base: 'ring-2 -me-1.5' }, md: { base: 'ring-2 -me-1.5' }, lg: { base: 'ring-2 -me-1.5' }, xl: { base: 'ring-3 -me-2' }, '2xl': { base: 'ring-3 -me-2' }, '3xl': { base: 'ring-3 -me-2' } } }, defaultVariants: { size: 'md' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/AvatarGroup.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/avatar-group.ts). # Badge ## Usage Use the default slot to set the label of the Badge. ```vue ``` ### Label Use the `label` prop to set the label of the Badge. ```vue ``` ### Color Use the `color` prop to change the color of the Badge. ```vue ``` ### Variant Use the `variant` props to change the variant of the Badge. ```vue ``` ### Size Use the `size` prop to change the size of the Badge. ```vue ``` ### Icon Use the `icon` prop to show an [Icon](https://ui.nuxt.com/docs/components/icon) inside the Badge. ```vue ``` Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position. ```vue ``` ### Avatar Use the `avatar` prop to show an [Avatar](https://ui.nuxt.com/docs/components/avatar) inside the Badge. ```vue ``` ## Examples ### `class` prop Use the `class` prop to override the base styles of the Badge. ```vue ``` ## API ### Props ```ts /** * Props for the Badge component */ interface BadgeProps { /** * The element or component this component should render as. * @default "\"span\"" */ as?: any; label?: string | number | undefined; color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; variant?: "solid" | "outline" | "soft" | "subtle" | undefined; size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined; /** * Render the badge with equal padding on all sides. */ square?: boolean | undefined; ui?: { base?: ClassNameValue; label?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; trailingIcon?: ClassNameValue; } | undefined; /** * Display an icon based on the `leading` and `trailing` props. */ icon?: any; /** * Display an avatar on the left side. */ avatar?: AvatarProps | undefined; /** * When `true`, the icon will be displayed on the left side. */ leading?: boolean | undefined; /** * Display an icon on the left side. */ leadingIcon?: any; /** * When `true`, the icon will be displayed on the right side. */ trailing?: boolean | undefined; /** * Display an icon on the right side. */ trailingIcon?: any; } ``` ### Slots ```ts /** * Slots for the Badge component */ interface BadgeSlots { leading(): any; default(): any; trailing(): any; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { badge: { slots: { base: 'font-medium inline-flex items-center', label: 'truncate', leadingIcon: 'shrink-0', leadingAvatar: 'shrink-0', leadingAvatarSize: '', trailingIcon: 'shrink-0' }, variants: { fieldGroup: { horizontal: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]', vertical: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]' }, color: { primary: '', secondary: '', success: '', info: '', warning: '', error: '', neutral: '' }, variant: { solid: '', outline: '', soft: '', subtle: '' }, size: { xs: { base: 'text-[8px]/3 px-1 py-0.5 gap-1 rounded-sm', leadingIcon: 'size-3', leadingAvatarSize: '3xs', trailingIcon: 'size-3' }, sm: { base: 'text-[10px]/3 px-1.5 py-1 gap-1 rounded-sm', leadingIcon: 'size-3', leadingAvatarSize: '3xs', trailingIcon: 'size-3' }, md: { base: 'text-xs px-2 py-1 gap-1 rounded-md', leadingIcon: 'size-4', leadingAvatarSize: '3xs', trailingIcon: 'size-4' }, lg: { base: 'text-sm px-2 py-1 gap-1.5 rounded-md', leadingIcon: 'size-5', leadingAvatarSize: '2xs', trailingIcon: 'size-5' }, xl: { base: 'text-base px-2.5 py-1 gap-1.5 rounded-md', leadingIcon: 'size-6', leadingAvatarSize: '2xs', trailingIcon: 'size-6' } }, square: { true: '' } }, compoundVariants: [ { color: 'primary', variant: 'solid', class: 'bg-primary text-inverted' }, { color: 'secondary', variant: 'solid', class: 'bg-secondary text-inverted' }, { color: 'success', variant: 'solid', class: 'bg-success text-inverted' }, { color: 'info', variant: 'solid', class: 'bg-info text-inverted' }, { color: 'warning', variant: 'solid', class: 'bg-warning text-inverted' }, { color: 'error', variant: 'solid', class: 'bg-error text-inverted' }, { color: 'primary', variant: 'outline', class: 'text-primary ring ring-inset ring-primary/50' }, { color: 'secondary', variant: 'outline', class: 'text-secondary ring ring-inset ring-secondary/50' }, { color: 'success', variant: 'outline', class: 'text-success ring ring-inset ring-success/50' }, { color: 'info', variant: 'outline', class: 'text-info ring ring-inset ring-info/50' }, { color: 'warning', variant: 'outline', class: 'text-warning ring ring-inset ring-warning/50' }, { color: 'error', variant: 'outline', class: 'text-error ring ring-inset ring-error/50' }, { color: 'primary', variant: 'soft', class: 'bg-primary/10 text-primary' }, { color: 'secondary', variant: 'soft', class: 'bg-secondary/10 text-secondary' }, { color: 'success', variant: 'soft', class: 'bg-success/10 text-success' }, { color: 'info', variant: 'soft', class: 'bg-info/10 text-info' }, { color: 'warning', variant: 'soft', class: 'bg-warning/10 text-warning' }, { color: 'error', variant: 'soft', class: 'bg-error/10 text-error' }, { color: 'primary', variant: 'subtle', class: 'bg-primary/10 text-primary ring ring-inset ring-primary/25' }, { color: 'secondary', variant: 'subtle', class: 'bg-secondary/10 text-secondary ring ring-inset ring-secondary/25' }, { color: 'success', variant: 'subtle', class: 'bg-success/10 text-success ring ring-inset ring-success/25' }, { color: 'info', variant: 'subtle', class: 'bg-info/10 text-info ring ring-inset ring-info/25' }, { color: 'warning', variant: 'subtle', class: 'bg-warning/10 text-warning ring ring-inset ring-warning/25' }, { color: 'error', variant: 'subtle', class: 'bg-error/10 text-error ring ring-inset ring-error/25' }, { color: 'neutral', variant: 'solid', class: 'text-inverted bg-inverted' }, { color: 'neutral', variant: 'outline', class: 'ring ring-inset ring-accented text-default bg-default' }, { color: 'neutral', variant: 'soft', class: 'text-default bg-elevated' }, { color: 'neutral', variant: 'subtle', class: 'ring ring-inset ring-accented text-default bg-elevated' }, { size: 'xs', square: true, class: 'p-0.5' }, { size: 'sm', square: true, class: 'p-1' }, { size: 'md', square: true, class: 'p-1' }, { size: 'lg', square: true, class: 'p-1' }, { size: 'xl', square: true, class: 'p-1' } ], defaultVariants: { color: 'primary', variant: 'solid', size: 'md' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Badge.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/badge.ts). # Banner ## Usage ### Title Use the `title` prop to display a title on the Banner. ```vue ``` ### Icon Use the `icon` prop to display an icon on the Banner. ```vue ``` ### Color Use the `color` prop to change the color of the Banner. ```vue ``` ### Close Use the `close` prop to display a [Button](https://ui.nuxt.com/docs/components/button) to dismiss the Banner. Defaults to `false`. \> \[!TIP] \> A \`close\` event will be emitted when the close button is clicked. ```vue [BannerExample.vue] ``` \> \[!NOTE] \> When closed, \`banner-${id}\` will be stored in the local storage to prevent it from being displayed again. For the example above, \`banner-example\` will be stored in the local storage. \> \[!CAUTION] \> To persist the dismissed state across page reloads, you must specify an \`id\` prop. Without an explicit \`id\`, the banner will only be hidden for the current session and will reappear on page reload. ### Close Icon Use the `close-icon` prop to customize the close button [Icon](https://ui.nuxt.com/docs/components/icon). Defaults to `i-lucide-x`. ```vue [BannerExample.vue] ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/nuxt#theme \> You can customize this icon globally in your \`app.config.ts\` under \`ui.icons.close\` key. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/vue#theme \> You can customize this icon globally in your \`vite.config.ts\` under \`ui.icons.close\` key. ### Actions Use the `actions` prop to add some [Button](https://ui.nuxt.com/docs/components/button) actions to the Banner. ```vue ``` \> \[!NOTE] \> The action buttons default to \`color="neutral"\` and \`size="xs"\`. You can customize these values by passing them directly to each action button. ### Link You can pass any property from the [``](https://nuxt.com/docs/api/components/nuxt-link){rel=""nofollow""} component such as `to`, `target`, `rel`, etc. ```vue ``` \> \[!NOTE] \> The \`NuxtLink\` component will inherit all other attributes you pass to the \`User\` component. ## Examples ### Within `app.vue` Use the Banner component in your `app.vue` or in a layout: ```vue [app.vue] {3} ``` ## API ### Props ```ts /** * Props for the Banner component */ interface BannerProps { /** * The element or component this component should render as. */ as?: any; /** * A unique id saved to local storage to remember if the banner has been dismissed. * Without an explicit id, the banner will not be persisted and will reappear on page reload. */ id?: string | undefined; /** * The icon displayed next to the title. */ icon?: any; title?: string | undefined; /** * Display a list of actions next to the title. * `{ color: 'neutral', size: 'xs' }`{lang="ts-type"} */ actions?: ButtonProps[] | undefined; to?: string | St | vt | undefined; target?: "_blank" | "_parent" | "_self" | "_top" | (string & {}) | null | undefined; color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; /** * Display a close button to dismiss the banner. * `{ size: 'md', color: 'neutral', variant: 'ghost' }`{lang="ts-type"} */ close?: boolean | Omit | undefined; /** * The icon displayed in the close button. */ closeIcon?: any; ui?: { root?: ClassNameValue; container?: ClassNameValue; left?: ClassNameValue; center?: ClassNameValue; right?: ClassNameValue; icon?: ClassNameValue; title?: ClassNameValue; actions?: ClassNameValue; close?: ClassNameValue; } | undefined; } ``` ### Slots ```ts /** * Slots for the Banner component */ interface BannerSlots { leading(): any; title(): any; actions(): any; close(): any; } ``` ### Emits ```ts /** * Emitted events for the Banner component */ interface BannerEmits { close: (payload: []) => void; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { banner: { slots: { root: [ 'relative z-50 w-full', 'transition-colors' ], container: 'flex items-center justify-between gap-3 h-12', left: 'hidden lg:flex-1 lg:flex lg:items-center', center: 'flex items-center gap-1.5 min-w-0', right: 'lg:flex-1 flex items-center justify-end', icon: 'size-5 shrink-0 text-inverted pointer-events-none', title: 'text-sm text-inverted font-medium truncate', actions: 'flex gap-1.5 shrink-0 isolate', close: 'text-inverted hover:bg-default/10 focus-visible:bg-default/10 -me-1.5 lg:me-0' }, variants: { color: { primary: { root: 'bg-primary' }, secondary: { root: 'bg-secondary' }, success: { root: 'bg-success' }, info: { root: 'bg-info' }, warning: { root: 'bg-warning' }, error: { root: 'bg-error' }, neutral: { root: 'bg-inverted' } }, to: { true: '' } }, compoundVariants: [ { color: 'primary', to: true, class: { root: 'hover:bg-primary/90' } }, { color: 'secondary', to: true, class: { root: 'hover:bg-secondary/90' } }, { color: 'success', to: true, class: { root: 'hover:bg-success/90' } }, { color: 'info', to: true, class: { root: 'hover:bg-info/90' } }, { color: 'warning', to: true, class: { root: 'hover:bg-warning/90' } }, { color: 'error', to: true, class: { root: 'hover:bg-error/90' } }, { color: 'neutral', to: true, class: { root: 'hover:bg-inverted/90' } } ], defaultVariants: { color: 'primary' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Banner.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/banner.ts). # BlogPost ## Usage The BlogPost component provides a flexible way to display an `
` element with customizable content including title, description, image, etc. ```vue ``` \> \[!TIP] \> See: /docs/components/blog-posts \> Use the \`BlogPosts\` component to display multiple blog posts in a responsive grid layout. ### Title Use the `title` prop to display the title of the BlogPost. ```vue ``` ### Description Use the `description` prop to display the description of the BlogPost. ```vue ``` ### Date Use the `date` prop to display the date of the BlogPost. \> \[!TIP] \> The date is automatically formatted to the \[current locale]\(/docs/getting-started/integrations/i18n/nuxt#locale). You can either pass a \`Date\` object or a string. ```vue ``` ### Badge Use the `badge` prop to display a [Badge](https://ui.nuxt.com/docs/components/badge) in the BlogPost. ```vue ``` You can pass any property from the [Badge](https://ui.nuxt.com/docs/components/badge#props) component to customize it. ```vue ``` ### Image Use the `image` prop to display an image in the BlogPost. \> \[!NOTE] \> If \[\`@nuxt/image\`]\(https\://image.nuxt.com/get-started/installation) is installed, the \`\\` component will be used instead of the native \`img\` tag. ```vue ``` ### Authors Use the `authors` prop to display a list of [User](https://ui.nuxt.com/docs/components/user) in the BlogPost as an array of objects with the following properties: - `name?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `description?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `avatar?: Omit`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `chip?: boolean | Omit`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `size?: UserProps['size']`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `orientation?: UserProps['orientation']`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} You can pass any property from the [Link](https://ui.nuxt.com/docs/components/link#props) component such as `to`, `target`, etc. ```vue ``` When the `authors` prop has more than one item, the [AvatarGroup](https://ui.nuxt.com/docs/components/avatar-group) component is used. ```vue ``` ### Link You can pass any property from the [``](https://nuxt.com/docs/api/components/nuxt-link){rel=""nofollow""} component such as `to`, `target`, `rel`, etc. ```vue ``` ### Variant Use the `variant` prop to change the style of the BlogPost. ```vue ``` \> \[!NOTE] \> The styling will be different wether you provide a \`to\` prop or an \`image\`. ### Orientation Use the `orientation` prop to change the BlogPost orientation. Defaults to `vertical`. ```vue ``` ## API ### Props ```ts /** * Props for the BlogPost component */ interface BlogPostProps { /** * The element or component this component should render as. * @default "\"article\"" */ as?: any; title?: string | undefined; description?: string | undefined; /** * The date of the blog post. Can be a string or a Date object. */ date?: string | Date | undefined; /** * Display a badge on the blog post. * Can be a string or an object. * `{ color: 'neutral', variant: 'subtle' }`{lang="ts-type"} */ badge?: string | BadgeProps | undefined; /** * The authors of the blog post. */ authors?: UserProps[] | undefined; /** * The image of the blog post. Can be a string or an object. */ image?: string | (Partial & { [key: string]: any; }) | undefined; /** * The orientation of the blog post. * @default "\"vertical\"" */ orientation?: "vertical" | "horizontal" | undefined; variant?: "outline" | "soft" | "subtle" | "ghost" | "naked" | undefined; to?: string | St | vt | undefined; target?: "_blank" | "_parent" | "_self" | "_top" | (string & {}) | null | undefined; onClick?: ((event: MouseEvent) => void | Promise) | undefined; ui?: { root?: ClassNameValue; header?: ClassNameValue; body?: ClassNameValue; footer?: ClassNameValue; image?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; authors?: ClassNameValue; avatar?: ClassNameValue; meta?: ClassNameValue; date?: ClassNameValue; badge?: ClassNameValue; } | undefined; } ``` ### Slots ```ts /** * Slots for the BlogPost component */ interface BlogPostSlots { date(): any; badge(): any; title(): any; description(): any; authors(): any; header(): any; body(): any; footer(): any; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { blogPost: { slots: { root: 'relative group/blog-post flex flex-col rounded-lg overflow-hidden', header: 'relative overflow-hidden aspect-[16/9] w-full pointer-events-none', body: 'min-w-0 flex-1 flex flex-col', footer: '', image: 'object-cover object-top w-full h-full', title: 'text-xl text-pretty font-semibold text-highlighted', description: 'mt-1 text-base text-pretty', authors: 'pt-4 mt-auto flex flex-wrap gap-x-3 gap-y-1.5', avatar: '', meta: 'flex items-center gap-2 mb-2', date: 'text-sm', badge: '' }, variants: { orientation: { horizontal: { root: 'lg:grid lg:grid-cols-2 lg:items-center gap-x-8', body: 'justify-center p-4 sm:p-6 lg:px-0' }, vertical: { root: 'flex flex-col', body: 'p-4 sm:p-6' } }, variant: { outline: { root: 'bg-default ring ring-default', date: 'text-toned', description: 'text-muted' }, soft: { root: 'bg-elevated/50', date: 'text-muted', description: 'text-toned' }, subtle: { root: 'bg-elevated/50 ring ring-default', date: 'text-muted', description: 'text-toned' }, ghost: { date: 'text-toned', description: 'text-muted', header: 'shadow-lg rounded-lg' }, naked: { root: 'p-0 sm:p-0', date: 'text-toned', description: 'text-muted', header: 'shadow-lg rounded-lg' } }, to: { true: { root: [ 'has-focus-visible:ring-2 has-focus-visible:ring-primary', 'transition' ], image: 'transform transition-transform duration-200 group-hover/blog-post:scale-110', avatar: 'transform transition-transform duration-200 hover:scale-115 focus-visible:outline-primary' } }, image: { true: '' } }, compoundVariants: [ { variant: 'outline', to: true, class: { root: 'hover:bg-elevated/50' } }, { variant: 'soft', to: true, class: { root: 'hover:bg-elevated' } }, { variant: 'subtle', to: true, class: { root: 'hover:bg-elevated hover:ring-accented' } }, { variant: 'ghost', to: true, class: { root: 'hover:bg-elevated/50', header: [ 'group-hover/blog-post:shadow-none', 'transition-all' ] } }, { variant: 'ghost', to: true, orientation: 'vertical', class: { header: 'group-hover/blog-post:rounded-b-none' } }, { variant: 'ghost', to: true, orientation: 'horizontal', class: { header: 'group-hover/blog-post:rounded-r-none' } }, { orientation: 'vertical', image: false, variant: 'naked', class: { body: 'p-0 sm:p-0' } } ], defaultVariants: { variant: 'outline' } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/BlogPost.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/blog-post.ts). # BlogPosts ## Usage The BlogPosts component provides a flexible layout to display a list of [BlogPost](https://ui.nuxt.com/docs/components/blog-post) components using either the default slot or the `posts` prop. ```vue {2,8} ``` ### Posts Use the `posts` prop as an array of objects with the properties of the [BlogPost](https://ui.nuxt.com/docs/components/blog-post#props) component. ```vue ``` ### Orientation Use the `orientation` prop to change the orientation of the BlogPosts. Defaults to `horizontal`. ```vue ``` \> \[!TIP] \> When using the \`posts\` prop instead of the default slot, the \`orientation\` of the posts is automatically reversed, \`horizontal\` to \`vertical\` and vice versa. ## Examples \> \[!NOTE] \> While these examples use \[Nuxt Content]\(https\://content.nuxt.com), the components can be integrated with any content management system. ### Within a page Use the BlogPosts component in a page to create a blog page: ```vue [pages/blog/index.vue] {11-18} ``` \> \[!NOTE] \> In this example, the \`posts\` are fetched using \`queryCollection\` from the \`@nuxt/content\` module. \> \[!TIP] \> The \`to\` prop is overridden here since \`@nuxt/content\` uses the \`path\` property. ## API ### Props ```ts /** * Props for the BlogPosts component */ interface BlogPostsProps { /** * The element or component this component should render as. */ as?: any; posts?: BlogPostProps[] | undefined; /** * The orientation of the blog posts. * @default "\"horizontal\"" */ orientation?: "horizontal" | "vertical" | undefined; ui?: { base?: any; } | undefined; } ``` ### Slots ```ts /** * Slots for the BlogPosts component */ interface BlogPostsSlots { date(): any; badge(): any; title(): any; description(): any; authors(): any; header(): any; body(): any; footer(): any; default(): any; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { blogPosts: { base: 'flex flex-col gap-8 lg:gap-y-16', variants: { orientation: { horizontal: 'sm:grid sm:grid-cols-2 lg:grid-cols-3', vertical: '' } } } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/BlogPosts.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/blog-posts.ts). # Breadcrumb ## Usage Use the Breadcrumb component to show the current page's location in your site's hierarchy. ```vue ``` ### Items Use the `items` prop as an array of objects with the following properties: - `label?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `icon?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `avatar?: AvatarProps`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - [`slot?: string`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"}](https://ui.nuxt.com/#with-custom-slot) - `class?: any`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `ui?: { item?: ClassNameValue, link?: ClassNameValue, linkLeadingIcon?: ClassNameValue, linkLeadingAvatar?: ClassNameValue, linkLabel?: ClassNameValue, separator?: ClassNameValue, separatorIcon?: ClassNameValue }`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} You can pass any property from the [Link](https://ui.nuxt.com/docs/components/link#props) component such as `to`, `target`, etc. ```vue ``` \> \[!NOTE] \> A \`span\` is rendered instead of a link when the \`to\` property is not defined. ### Separator Icon Use the `separator-icon` prop to customize the [Icon](https://ui.nuxt.com/docs/components/icon) between each item. Defaults to `i-lucide-chevron-right`. ```vue ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/nuxt#theme \> You can customize this icon globally in your \`app.config.ts\` under \`ui.icons.chevronRight\` key. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/vue#theme \> You can customize this icon globally in your \`vite.config.ts\` under \`ui.icons.chevronRight\` key. ## Examples ### With separator slot Use the `#separator` slot to customize the separator between each item. ```vue [BreadcrumbSeparatorSlotExample.vue] ``` ### With custom slot Use the `slot` property to customize a specific item. You will have access to the following slots: - `#{{ item.slot }}`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `#{{ item.slot }}-leading`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `#{{ item.slot }}-label`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} - `#{{ item.slot }}-trailing`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} ```vue [BreadcrumbCustomSlotExample.vue] ``` \> \[!TIP] \> See: #slots \> You can also use the \`#item\`, \`#item-leading\`, \`#item-label\` and \`#item-trailing\` slots to customize all items. ## API ### Props ```ts /** * Props for the Breadcrumb component */ interface BreadcrumbProps { /** * The element or component this component should render as. * @default "\"nav\"" */ as?: any; items?: T[] | undefined; /** * The icon to use as a separator. */ separatorIcon?: any; /** * The key used to get the label from the item. * @default "\"label\"" */ labelKey?: GetItemKeys | undefined; ui?: { root?: ClassNameValue; list?: ClassNameValue; item?: ClassNameValue; link?: ClassNameValue; linkLeadingIcon?: ClassNameValue; linkLeadingAvatar?: ClassNameValue; linkLeadingAvatarSize?: ClassNameValue; linkLabel?: ClassNameValue; separator?: ClassNameValue; separatorIcon?: ClassNameValue; } | undefined; } ``` ### Slots ```ts /** * Slots for the Breadcrumb component */ interface BreadcrumbSlots { item(): any; item-leading(): any; item-label(): any; item-trailing(): any; separator(): any; } ``` ## Theme ```ts [app.config.ts] export default defineAppConfig({ ui: { breadcrumb: { slots: { root: 'relative min-w-0', list: 'flex items-center gap-1.5', item: 'flex min-w-0', link: 'group relative flex items-center gap-1.5 text-sm min-w-0 focus-visible:outline-primary', linkLeadingIcon: 'shrink-0 size-5', linkLeadingAvatar: 'shrink-0', linkLeadingAvatarSize: '2xs', linkLabel: 'truncate', separator: 'flex', separatorIcon: 'shrink-0 size-5 text-muted' }, variants: { active: { true: { link: 'text-primary font-semibold' }, false: { link: 'text-muted font-medium' } }, disabled: { true: { link: 'cursor-not-allowed opacity-75' } }, to: { true: '' } }, compoundVariants: [ { disabled: false, active: false, to: true, class: { link: [ 'hover:text-default', 'transition-colors' ] } } ] } } }) ``` ## Changelog See commit history for \[component]\(https\://github.com/nuxt/ui/commits/v4/src/runtime/components/Breadcrumb.vue) and \[theme]\(https\://github.com/nuxt/ui/commits/v4/src/theme/breadcrumb.ts). # Button ## Usage Use the default slot to set the label of the Button. ```vue ``` ### Label Use the `label` prop to set the label of the Button. ```vue ``` ### Color Use the `color` prop to change the color of the Button. ```vue ``` ### Variant Use the `variant` prop to change the variant of the Button. ```vue ``` ### Size Use the `size` prop to change the size of the Button. ```vue ``` ### Icon Use the `icon` prop to show an [Icon](https://ui.nuxt.com/docs/components/icon) inside the Button. ```vue ``` Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position. ```vue ``` The `label` as prop or slot is optional so you can use the Button as an icon-only button. ```vue ``` ### Avatar Use the `avatar` prop to show an [Avatar](https://ui.nuxt.com/docs/components/avatar) inside the Button. ```vue ``` The `label` as prop or slot is optional so you can use the Button as an avatar-only button. ```vue ``` ### Link You can pass any property from the [Link](https://ui.nuxt.com/docs/components/link#props) component such as `to`, `target`, etc. ```vue ``` When the Button is a link or when using the `active` prop, you can use the `active-color` and `active-variant` props to customize the active state. ```vue ``` You can also use the `active-class` and `inactive-class` props to customize the active state. ```vue ``` \> \[!TIP] \> You can configure these styles globally in your \`app.config.ts\` file under the \`ui.button.variants.active\` key. \> \`\`\`ts \> export default defineAppConfig({ \> ui: { \> button: { \> variants: { \> active: { \> true: { \> base: 'font-bold' \> } \> } \> } \> } \> } \> }) \> \> \`\`\` ### Loading Use the `loading` prop to show a loading icon and disable the Button. ```vue ``` Use the `loading-auto` prop to show the loading icon automatically while the `@click` promise is pending. ```vue [ButtonLoadingAutoExample.vue] ``` This also works with the [Form](https://ui.nuxt.com/docs/components/form) component. ```vue [ButtonLoadingAutoFormExample.vue] ``` ### Loading Icon Use the `loading-icon` prop to customize the loading icon. Defaults to `i-lucide-loader-circle`. ```vue ``` \*\*Nuxt:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/nuxt#theme \> You can customize this icon globally in your \`app.config.ts\` under \`ui.icons.loading\` key. \*\*Vue:\*\* \> \[!TIP] \> See: /docs/getting-started/integrations/icons/vue#theme \> You can customize this icon globally in your \`vite.config.ts\` under \`ui.icons.loading\` key. ### Disabled Use the `disabled` prop to disable the Button. ```vue ``` ## Examples ### `class` prop Use the `class` prop to override the base styles of the Button. ```vue ``` ### `ui` prop Use the `ui` prop to override the slots styles of the Button. ```vue ``` ## API ### Props ```ts /** * Props for the Button component */ interface ButtonProps { label?: string | undefined; color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; activeColor?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; variant?: "solid" | "outline" | "soft" | "subtle" | "ghost" | "link" | undefined; activeVariant?: "solid" | "outline" | "soft" | "subtle" | "ghost" | "link" | undefined; size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined; /** * Render the button with equal padding on all sides. */ square?: boolean | undefined; /** * Render the button full width. */ block?: boolean | undefined; /** * Set loading state automatically based on the `@click` promise state */ loadingAuto?: boolean | undefined; onClick?: ((event: MouseEvent) => void | Promise) | ((event: MouseEvent) => void | Promise)[] | undefined; ui?: { base?: ClassNameValue; label?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; trailingIcon?: ClassNameValue; } | undefined; /** * Display an icon based on the `leading` and `trailing` props. */ icon?: any; /** * Display an avatar on the left side. */ avatar?: AvatarProps | undefined; /** * When `true`, the icon will be displayed on the left side. */ leading?: boolean | undefined; /** * Display an icon on the left side. */ leadingIcon?: any; /** * When `true`, the icon will be displayed on the right side. */ trailing?: boolean | undefined; /** * Display an icon on the right side. */ trailingIcon?: any; /** * When `true`, the loading icon will be displayed. */ loading?: boolean | undefined; /** * The icon when the `loading` prop is `true`. */ loadingIcon?: any; /** * Route Location the link should navigate to when clicked on. */ to?: string | St | vt | undefined; /** * Class to apply when the link is active */ activeClass?: string | undefined; /** * Class to apply when the link is exact active */ exactActiveClass?: string | undefined; /** * Value passed to the attribute `aria-current` when the link is exact active. */ ariaCurrentValue?: "page" | "step" | "location" | "date" | "time" | "true" | "false" | undefined; /** * Pass the returned promise of `router.push()` to `document.startViewTransition()` if supported. */ viewTransition?: boolean | undefined; /** * Calls `router.replace` instead of `router.push`. */ replace?: boolean | undefined; autofocus?: Booleanish | undefined; disabled?: boolean | undefined; form?: string | undefined; formaction?: string | undefined; formenctype?: string | undefined; formmethod?: string | undefined; formnovalidate?: Booleanish | undefined; formtarget?: string | undefined; name?: string | undefined; /** * The type of the button when not a link. */ type?: "reset" | "submit" | "button" | undefined; download?: any; /** * An alias for `to`. If used with `to`, `href` will be ignored */ href?: string | St | vt | undefined; hreflang?: string | undefined; media?: string | undefined; ping?: string | undefined; /** * A rel attribute value to apply on the link. Defaults to "noopener noreferrer" for external links. */ rel?: "noopener" | "noreferrer" | "nofollow" | "sponsored" | "ugc" | (string & {}) | null | undefined; /** * Where to display the linked URL, as the name for a browsing context. */ target?: (string & {}) | "_blank" | "_parent" | "_self" | "_top" | null | undefined; referrerpolicy?: HTMLAttributeReferrerPolicy | undefined; /** * The element or component this component should render as when not a link. */ as?: any; /** * Force the link to be active independent of the current route. */ active?: boolean | undefined; /** * Will only be active if the current route is an exact match. */ exact?: boolean | undefined; /** * Allows controlling how the current route query sets the link as active. */ exactQuery?: boolean | "partial" | undefined; /** * Will only be active if the current route hash is an exact match. */ exactHash?: boolean | undefined; /** * The class to apply when the link is inactive. */ inactiveClass?: string | undefined; /** * Forces the link to be considered as external (true) or internal (false). This is helpful to handle edge-cases */ external?: boolean | undefined; /** * If set to true, no rel attribute will be added to the link */ noRel?: boolean | undefined; /** * A class to apply to links that have been prefetched. */ prefetchedClass?: string | undefined; /** * When enabled will prefetch middleware, layouts and payloads of links in the viewport. */ prefetch?: boolean | undefined; /** * Allows controlling when to prefetch links. By default, prefetch is triggered only on visibility. */ prefetchOn?: "visibility" | "interaction" | Partial<{ visibility: boolean; interaction: boolean; }> | undefined; /** * Escape hatch to disable `prefetch` attribute. */ noPrefetch?: boolean | undefined; /** * An option to either add or remove trailing slashes in the `href` for this specific link. * Overrides the global `trailingSlash` option if provided. */ trailingSlash?: "remove" | "append" | undefined; } ``` \> \[!NOTE] \> See: https\://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes \> This component also supports all native \`\