Usage
Items
Use the items
prop as an array of objects with the following properties:
label?: string
icon?: string
trailingIcon?: string
content?: string
value?: string
disabled?: boolean
slot?: string
class?: any
ui?: { item?: ClassNameValue, header?: ClassNameValue, trigger?: ClassNameValue, leadingIcon?: ClassNameValue, label?: ClassNameValue, trailingIcon?: ClassNameValue, content?: ClassNameValue, body?: ClassNameValue }
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion :items="items" />
</template>
Multiple
Set the type
prop to multiple
to allow multiple items to be active at the same time. Defaults to single
.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion type="multiple" :items="items" />
</template>
Collapsible
When type
is single
, you can set the collapsible
prop to false
to prevent the active item from collapsing.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion :collapsible="false" :items="items" />
</template>
Unmount
Use the unmount-on-hide
prop to prevent the content from being unmounted when the accordion is collapsed. Defaults to true
.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion :unmount-on-hide="false" :items="items" />
</template>
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.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.',
disabled: true
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion disabled :items="items" />
</template>
Trailing Icon
Use the trailing-icon
prop to customize the trailing Icon of each item. Defaults to i-lucide-chevron-down
.
trailingIcon
property in the item object.<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.',
trailingIcon: 'i-lucide-plus'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion trailing-icon="i-lucide-arrow-down" :items="items" />
</template>
Examples
Control active item(s)
You can control the active item(s) by using the default-value
prop or the v-model
directive with the index of the item.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
]
const active = ref('0')
// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
setInterval(() => {
active.value = String((Number(active.value) + 1) % items.length)
}, 2000)
})
</script>
<template>
<UAccordion v-model="active" :items="items" />
</template>
value
of one of the items if provided.type="multiple"
, ensure to pass an array to the default-value
prop or the v-model
directive.With drag and drop
Use the useSortable
composable from @vueuse/integrations
to enable drag and drop functionality on the Accordion. This integration wraps Sortable.js to provide a seamless drag and drop experience.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
import { useSortable } from '@vueuse/integrations/useSortable'
const items = shallowRef<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
const accordion = useTemplateRef<HTMLElement>('accordion')
useSortable(accordion, items, {
animation: 150
})
</script>
<template>
<UAccordion ref="accordion" :items="items" />
</template>
With body slot
Use the #body
slot to customize the body of each item.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book'
},
{
label: 'Components',
icon: 'i-lucide-box'
}
]
</script>
<template>
<UAccordion :items="items">
<template #body="{ item }">
This is the {{ item.label }} panel.
</template>
</UAccordion>
</template>
#body
slot includes some pre-defined styles, use the #content
slot if you want to start from scratch.With content slot
Use the #content
slot to customize the content of each item.
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book'
},
{
label: 'Components',
icon: 'i-lucide-box'
}
]
</script>
<template>
<UAccordion :items="items">
<template #content="{ item }">
<p class="pb-3.5 text-sm text-muted">
This is the {{ item.label }} panel.
</p>
</template>
</UAccordion>
</template>
With custom slot
Use the slot
property to customize a specific item.
You will have access to the following slots:
#{{ item.slot }}
#{{ item.slot }}-body
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = [
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
slot: 'colors' as const,
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
] satisfies AccordionItem[]
</script>
<template>
<UAccordion :items="items">
<template #colors="{ item }">
<p class="text-sm pb-3.5 text-primary">
{{ item.content }}
</p>
</template>
</UAccordion>
</template>
With markdown content
You can use the MDC component from @nuxtjs/mdc
to render markdown in the accordion items.
<script setup lang="ts">
const items = [
{
label: 'What are the main considerations when upgrading to Nuxt UI v3?',
icon: 'i-lucide-circle-help',
content: 'The transition to v3 involves significant changes, including new component structures, updated theming approaches, and revised TypeScript definitions. We recommend a careful, incremental upgrade process, starting with thorough testing in a development environment.'
},
{
label: 'Is Nuxt UI v3 compatible with standalone Vue projects?',
icon: 'i-lucide-circle-help',
content: 'Nuxt UI is now compatible with Vue! You can follow the [installation guide](/docs/getting-started/installation/vue) to get started.'
},
{
label: 'Will Nuxt UI v3 work with other CSS frameworks like UnoCSS?',
icon: 'i-lucide-circle-help',
content: 'Nuxt UI v3 is currently designed to work exclusively with Tailwind CSS. While there\'s interest in UnoCSS support, implementing it would require significant changes to the theme structure due to differences in class naming conventions. As a result, we don\'t have plans to add UnoCSS support in v3.'
},
{
label: 'How does Nuxt UI v3 handle accessibility?',
icon: 'i-lucide-circle-help',
content: 'Nuxt UI v3 enhances accessibility through Reka UI integration. This provides automatic ARIA attributes, keyboard navigation support, intelligent focus management, and screen reader announcements. While offering a strong foundation, proper implementation and testing in your specific use case remains crucial for full accessibility compliance. For more detailed information, refer to [Reka UI\'s accessibility documentation](https://reka-ui.com/docs/overview/accessibility).'
},
{
label: 'What is the testing approach for Nuxt UI v3?',
icon: 'i-lucide-circle-help',
content: 'Nuxt UI v3 ensures reliability with 1000+ Vitest tests, covering core functionality and accessibility. This robust testing suite supports the library\'s stability and serves as a reference for developers.'
},
{
label: 'Is this version stable and suitable for production use?',
icon: 'i-lucide-circle-help',
content: 'As Nuxt UI v3 is currently in alpha, we recommend thorough testing before using it in production environments. We\'re actively working on stabilization and welcome feedback from early adopters to improve the library. Feel free to report any issues you encounter on our [GitHub repository](https://github.com/nuxt/ui/issues).'
}
]
</script>
<template>
<UAccordion
type="multiple"
:items="items"
:unmount-on-hide="false"
:default-value="['0']"
:ui="{
trigger: 'text-base',
body: 'text-base text-muted'
}"
>
<template #body="{ item }">
<MDC :value="item.content" unwrap="p" />
</template>
</UAccordion>
</template>
API
Props
Prop | Default | Type |
---|---|---|
as |
|
The element or component this component should render as. |
items |
| |
trailingIcon |
|
The icon displayed on the right side of the trigger. |
labelKey |
|
The key used to get the label from the item. |
collapsible |
|
When type is "single", allows closing content when clicking trigger for an open item. When type is "multiple", this prop has no effect. |
defaultValue |
The default active value of the item(s). Use when you do not need to control the state of the item(s). | |
modelValue |
The controlled value of the active item(s). Use this when you need to control the state of the items. Can be binded with | |
type |
|
Determines whether a "single" or "multiple" items can be selected at a time. This prop will overwrite the inferred type from |
disabled |
|
When |
unmountOnHide |
|
When |
ui |
|
Slots
Slot | Type |
---|---|
leading |
|
default |
|
trailing |
|
content |
|
body |
|
Emits
Event | Type |
---|---|
update:modelValue |
|
Theme
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'
}
}
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
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'
}
}
}
}
}
})
]
})