Icons
Usage
Nuxt UI ships an Icon component backed by @iconify/vue, so there's no additional setup required.
Icon component
You can use the Icon component with a name prop to display an icon:
<template>
<UIcon name="i-lucide-lightbulb" class="size-5" />
</template>
search-icons MCP tool.-), 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.Component props
Some components also have an icon prop to display an icon, like the Button for example:
<template>
<UButton icon="i-lucide-sun" variant="subtle">Button</UButton>
</template>
Collections
Iconify dataset
It's highly recommended to install the icon data locally with:
pnpm i @iconify-json/{collection_name}
yarn add @iconify-json/{collection_name}
npm install @iconify-json/{collection_name}
For example, to use the i-lucide-lightbulb icon, install its collection with @iconify-json/lucide.
Installing the collection lets Nuxt UI embed the icons it uses into your build, so they render straight away during SSR and work fully offline instead of being fetched from the Iconify API at runtime. This happens automatically for Nuxt UI's own icons, from the lucide collection by default.
To bundle other icons, such as ones you override or use elsewhere in your app, add them to the icon.clientBundle.icons option in your vite.config.ts:
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
ui({
icon: {
clientBundle: {
icons: ['lucide:heart', 'simple-icons:github']
}
}
})
]
})
i-{collection}-{name} or {collection}:{name} form, for example i-lucide-heart or lucide:heart, and i-material-symbols-menu or material-symbols:menu. Install each collection you reference with @iconify-json/{collection_name}.To bundle the icons you use without listing them one by one, enable scan instead. It scans your source for icon usages from your installed collections and bundles them, the same way @nuxt/icon's clientBundle.scan works:
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
ui({
icon: {
clientBundle: {
scan: true
}
}
})
]
})
Scanning only reads .vue, .jsx, .tsx, .md, .mdc, .mdx, .yml and .yaml files, and it only matches icon names written as literal strings. Icons defined in a .ts or .js file, like a list of navigation links, are missed, as are names built dynamically like i-lucide-${name}. Set globInclude to scan those files as well. It replaces the default list, so keep the extensions you still need:
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
ui({
icon: {
clientBundle: {
scan: {
globInclude: ['**/*.{vue,jsx,tsx,md,mdc,mdx,yml,yaml,ts,js}']
}
}
}
})
]
})
Dynamic names can still be bundled when you know the whole set at build time, by listing them in clientBundle.icons. Names that only exist at runtime, like icons coming from an API, can't be bundled at all and are loaded from the Iconify API on demand.
Icons whose collection is not installed still load from the Iconify API at runtime, so install each collection you use with @iconify-json/{collection_name}. To opt out of bundling entirely, set icon.clientBundle to false.
Theme
You can change the default icons used by Nuxt UI components in your vite.config.ts:
export default defineAppConfig({
ui: {
icons: {
arrowDown: 'i-lucide-arrow-down',
arrowLeft: 'i-lucide-arrow-left',
arrowRight: 'i-lucide-arrow-right',
arrowUp: 'i-lucide-arrow-up',
caution: 'i-lucide-circle-alert',
check: 'i-lucide-check',
chevronDoubleLeft: 'i-lucide-chevrons-left',
chevronDoubleRight: 'i-lucide-chevrons-right',
chevronDown: 'i-lucide-chevron-down',
chevronLeft: 'i-lucide-chevron-left',
chevronRight: 'i-lucide-chevron-right',
chevronUp: 'i-lucide-chevron-up',
close: 'i-lucide-x',
copy: 'i-lucide-copy',
copyCheck: 'i-lucide-copy-check',
dark: 'i-lucide-moon',
drag: 'i-lucide-grip-vertical',
ellipsis: 'i-lucide-ellipsis',
error: 'i-lucide-circle-x',
external: 'i-lucide-arrow-up-right',
eye: 'i-lucide-eye',
eyeOff: 'i-lucide-eye-off',
file: 'i-lucide-file',
folder: 'i-lucide-folder',
folderOpen: 'i-lucide-folder-open',
hash: 'i-lucide-hash',
info: 'i-lucide-info',
light: 'i-lucide-sun',
loading: 'i-lucide-loader-circle',
menu: 'i-lucide-menu',
minus: 'i-lucide-minus',
panelClose: 'i-lucide-panel-left-close',
panelOpen: 'i-lucide-panel-left-open',
plus: 'i-lucide-plus',
reload: 'i-lucide-rotate-ccw',
search: 'i-lucide-search',
stop: 'i-lucide-square',
star: 'i-lucide-star',
success: 'i-lucide-circle-check',
system: 'i-lucide-monitor',
tip: 'i-lucide-lightbulb',
upload: 'i-lucide-upload',
warning: 'i-lucide-triangle-alert'
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
icons: {
arrowDown: 'i-lucide-arrow-down',
arrowLeft: 'i-lucide-arrow-left',
arrowRight: 'i-lucide-arrow-right',
arrowUp: 'i-lucide-arrow-up',
caution: 'i-lucide-circle-alert',
check: 'i-lucide-check',
chevronDoubleLeft: 'i-lucide-chevrons-left',
chevronDoubleRight: 'i-lucide-chevrons-right',
chevronDown: 'i-lucide-chevron-down',
chevronLeft: 'i-lucide-chevron-left',
chevronRight: 'i-lucide-chevron-right',
chevronUp: 'i-lucide-chevron-up',
close: 'i-lucide-x',
copy: 'i-lucide-copy',
copyCheck: 'i-lucide-copy-check',
dark: 'i-lucide-moon',
drag: 'i-lucide-grip-vertical',
ellipsis: 'i-lucide-ellipsis',
error: 'i-lucide-circle-x',
external: 'i-lucide-arrow-up-right',
eye: 'i-lucide-eye',
eyeOff: 'i-lucide-eye-off',
file: 'i-lucide-file',
folder: 'i-lucide-folder',
folderOpen: 'i-lucide-folder-open',
hash: 'i-lucide-hash',
info: 'i-lucide-info',
light: 'i-lucide-sun',
loading: 'i-lucide-loader-circle',
menu: 'i-lucide-menu',
minus: 'i-lucide-minus',
panelClose: 'i-lucide-panel-left-close',
panelOpen: 'i-lucide-panel-left-open',
plus: 'i-lucide-plus',
reload: 'i-lucide-rotate-ccw',
search: 'i-lucide-search',
stop: 'i-lucide-square',
star: 'i-lucide-star',
success: 'i-lucide-circle-check',
system: 'i-lucide-monitor',
tip: 'i-lucide-lightbulb',
upload: 'i-lucide-upload',
warning: 'i-lucide-triangle-alert'
}
}
})
]
})