用法
使用Accordion组件可显示可折叠项的列表。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Is Nuxt UI free to use?',
content: 'Yes! Nuxt UI is completely free and open source under the MIT license. All 125+ components are available to everyone.'
},
{
label: 'Can I use Nuxt UI with Vue without Nuxt?',
content: '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.'
},
{
label: 'Is Nuxt UI production-ready?',
content: 'Yes! Nuxt UI is used in production by thousands of applications with extensive tests, regular updates, and active maintenance.'
}
])
</script>
<template>
<UAccordion :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Is Nuxt UI free to use?',
content: 'Yes! Nuxt UI is completely free and open source under the MIT license. All 125+ components are available to everyone.'
},
{
label: 'Can I use Nuxt UI with Vue without Nuxt?',
content: '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.'
},
{
label: 'Is Nuxt UI production-ready?',
content: 'Yes! Nuxt UI is used in production by thousands of applications with extensive tests, regular updates, and active maintenance.'
}
])
</script>
<template>
<UAccordion :items="items" />
</template>项目
使用items prop作为具有以下属性的对象数组:
label?: stringicon?: stringtrailingIcon?: stringcontent?: stringvalue?: stringdisabled?: booleanslot?: stringclass?: anyui?: { 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><script setup lang="ts">
import { ref } from 'vue'
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>多个
将type属性设置为multiple,以允许多个项目同时处于活动状态。将其设置为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><script setup lang="ts">
import { ref } from 'vue'
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>可折叠
当type为single时,可以将collapsible属性设置为false,以防止活动项折叠。
<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><script setup lang="ts">
import { ref } from 'vue'
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-on-hide属性来防止折叠手风琴时内容被卸载。将其转换为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><script setup lang="ts">
import { ref } from 'vue'
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属性禁用折叠器。
您还可以使用item对象中的disabled属性禁用特定项。
<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><script setup lang="ts">
import { ref } from 'vue'
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属性将每个项目的尾随Icon自定义为i-lucide-chevron-down。
trailingIcon属性为特定项设置图标。<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><script setup lang="ts">
import { ref } from 'vue'
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>示例
active item(s)
您可以通过使用default-value prop或v-model指令与项目的value来控制活动项目。如果没有提供value,则默认为索引作为字符串。
<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>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
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>
v-model或default-value时,使用value-key属性更改用于匹配项的键。type="multiple"时,确保将数组传递给default-value prop或v-model指令。使用拖放
使用@vueuse/integrations中的useSortable组合可在Accordion上启用拖放功能。此集成包装Sortable.js以提供无缝拖放体验。
<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>
<script setup lang="ts">
import { shallowRef, useTemplateRef } from 'vue'
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>
带机身插槽
使用#body插槽自定义每个项目的主体。
<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插槽包括一些预定义的样式,如果您想从头开始,请使用#content插槽。带内容插槽
使用#content插槽自定义每个项目的内容。
<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>
带自定义插槽
使用slot属性可自定义特定项。
您将可以访问以下插槽:
#{{ 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>
带有markdown内容
您可以使用@comark/vue中的Markdown组件来呈现可折叠项中的markdown。
<script setup lang="ts">
import { Markdown } from '@comark/vue'
const items = [
{
label: 'Is Nuxt UI free to use?',
icon: 'i-lucide-circle-help',
content: 'Yes! Nuxt UI is completely free and open source under the MIT license. All 125+ components are available to everyone.'
},
{
label: 'Can I use Nuxt UI with Vue without Nuxt?',
icon: 'i-lucide-circle-help',
content: '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.'
},
{
label: 'Will Nuxt UI work with other CSS frameworks like UnoCSS?',
icon: 'i-lucide-circle-help',
content: 'No. Nuxt UI is designed exclusively for Tailwind CSS. UnoCSS support would require significant architecture changes due to different class naming conventions.'
},
{
label: 'How does Nuxt UI handle accessibility?',
icon: 'i-lucide-circle-help',
content: '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.'
},
{
label: 'How is Nuxt UI tested?',
icon: 'i-lucide-circle-help',
content: 'Nuxt UI ensures reliability with 1000+ Vitest tests covering core functionality and accessibility.'
},
{
label: 'Is Nuxt UI production-ready?',
icon: 'i-lucide-circle-help',
content: 'Yes! Nuxt UI is used in production by thousands of applications with extensive tests, regular updates, and active maintenance.'
}
]
</script>
<template>
<UAccordion
type="multiple"
:items="items"
:unmount-on-hide="false"
:default-value="['3']"
:ui="{
trigger: 'text-base',
body: 'text-base text-muted'
}"
>
<template #body="{ item }">
<Markdown :value="item.content" unwrap="p" />
</template>
</UAccordion>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
items | T[] | |
trailingIcon | appConfig.ui.icons.chevronDown | anyThe icon displayed on the right side of the trigger. |
valueKey | 'value' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>The key used to get the value from the item. |
labelKey | 'label' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>The key used to get the label from the item. |
collapsible | true | boolean When type is "single", allows closing content when clicking trigger for an open item. When type is "multiple", this prop has no effect. |
defaultValue | string | string[]The default active value of the item(s). Use when you do not need to control the state of the item(s). | |
modelValue | string | string[]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 | 'single' | "single" | "multiple"Determines whether a "single" or "multiple" items can be selected at a time. This prop will overwrite the inferred type from |
disabled | false | boolean When |
unmountOnHide | true | boolean When |
ui | { root?: SlotClass; item?: SlotClass; header?: SlotClass; trigger?: SlotClass; content?: SlotClass; body?: SlotClass; leadingIcon?: SlotClass; trailingIcon?: SlotClass; label?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
default | { item: T; index: number; open: boolean; } |
leading | { item: T; index: number; open: boolean; ui: object; } |
trailing | { item: T; index: number; open: boolean; ui: object; } |
content | { item: T; index: number; open: boolean; ui: object; } |
body | { item: T; index: number; open: boolean; ui: object; } |
发射
| Event | Type |
|---|---|
update:modelValue | [value: string | string[] | undefined] |
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 outline-primary/25 focus-visible:outline-3 min-w-0 rounded-md',
content: 'data-[state=open]:animate-[accordion-down_200ms_var(--ease-out)] data-[state=closed]:animate-[accordion-up_200ms_var(--ease-out)] data-[state=closed]: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 ease-out motion-reduce:transition-none',
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 outline-primary/25 focus-visible:outline-3 min-w-0 rounded-md',
content: 'data-[state=open]:animate-[accordion-down_200ms_var(--ease-out)] data-[state=closed]:animate-[accordion-up_200ms_var(--ease-out)] data-[state=closed]: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 ease-out motion-reduce:transition-none',
label: 'text-start break-words'
},
variants: {
disabled: {
true: {
trigger: 'cursor-not-allowed opacity-75'
}
}
}
}
}
})
]
})