Use the Accordion component to display a list of collapsible items.
<script setup lang="ts">
const items = ref([
{
label: 'Is it accessible?',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion :items="items" />
</template>
Use the items prop as an array of objects with the following properties:
label?: stringicon?: stringtrailingIcon?: stringcontent?: stringvalue?: stringdisabled?: booleanslot?: stringclass?: anypohon?: { item?: ClassNameValue; header?: ClassNameValue; trigger?: ClassNameValue; leadingIcon?: ClassNameValue; label?: ClassNameValue; trailingIcon?: ClassNameValue; content?: ClassNameValue; body?: ClassNameValue }<script setup lang="ts">
import type { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion :items="items" />
</template>
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 { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion type="multiple" :items="items" />
</template>
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 { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion :items="items" />
</template>
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 { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion :items="items" />
</template>
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 { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion disabled :items="items" />
</template>
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 { PAccordionItem } from 'pohon-ui'
const items = ref<PAccordionItem[]>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.'
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.'
}
])
</script>
<template>
<PAccordion trailing-icon="i-lucide:arrow-down" :items="items" />
</template>
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.
<script setup lang="ts">
import type { PAccordionItem } from 'pohon-ui';
import { onMounted, ref } from 'vue';
const items: Array<PAccordionItem> = [
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.',
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: 'Yes. It\'s unstyled by default, giving you freedom over the look and feel.',
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.',
},
];
const active = ref('0');
// !Warning: 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>
<PAccordion
v-model="active"
:items="items"
/>
</template>
type="multiple", ensure to pass an array to the default-value prop or the v-model directive.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 { PAccordionItem } from 'pohon-ui';
import { useSortable } from '@vueuse/integrations/useSortable';
import { shallowRef, useTemplateRef } from 'vue';
const items = shallowRef<Array<PAccordionItem>>([
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.',
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
content: 'Yes. It\'s unstyled by default, giving you freedom over the look and feel.',
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.',
},
]);
const accordion = useTemplateRef<HTMLElement>('accordion');
useSortable(accordion, items, {
animation: 150,
});
</script>
<template>
<PAccordion
ref="accordion"
:items="items"
/>
</template>
Use the #body slot to customize the body of each item.
<script setup lang="ts">
import type { PAccordionItem } from 'pohon-ui';
const items: Array<PAccordionItem> = [
{
label: 'Icons',
icon: 'i-lucide:smile',
},
{
label: 'Colors',
icon: 'i-lucide:swatch-book',
},
{
label: 'Components',
icon: 'i-lucide:box',
},
];
</script>
<template>
<PAccordion :items="items">
<template #body="{ item }">
This is the {{ item.label }} panel.
</template>
</PAccordion>
</template>
#body slot includes some pre-defined styles, use the #content slot if you want to start from scratch.Use the #content slot to customize the content of each item.
<script setup lang="ts">
import type { PAccordionItem } from 'pohon-ui';
const items: Array<PAccordionItem> = [
{
label: 'Icons',
icon: 'i-lucide:smile',
},
{
label: 'Colors',
icon: 'i-lucide:swatch-book',
},
{
label: 'Components',
icon: 'i-lucide:box',
},
];
</script>
<template>
<PAccordion :items="items">
<template #content="{ item }">
<p class="text-sm color-secondary pb-3.5">
This is the {{ item.label }} panel.
</p>
</template>
</PAccordion>
</template>
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 { PAccordionItem } from 'pohon-ui';
const items = [
{
label: 'Is it accessible?',
icon: 'i-lucide:smile',
content: 'Yes. It adheres to the WAI-ARIA design pattern.',
},
{
label: 'Is it unstyled?',
icon: 'i-lucide:swatch-book',
slot: 'colors' as const,
content: 'Yes. It\'s unstyled by default, giving you freedom over the look and feel.',
},
{
label: 'Can it be animated?',
icon: 'i-lucide:box',
content: 'Yes! You can use the transition prop to configure the animation.',
},
] satisfies Array<PAccordionItem>;
</script>
<template>
<PAccordion :items="items">
<template #colors="{ item }">
<p class="text-sm text-primary pb-3.5">
{{ item.content }}
</p>
</template>
</PAccordion>
</template>
You can use the MDC component from @nuxtjs/mdc to render markdown in the accordion items.
<script setup lang="ts">
const items = [
{
label: 'Is Pohon UI free to use?',
icon: 'i-lucide:circle-help',
content: 'Yes! Pohon UI is completely free and open source under the MIT license. All 100+ components are available to everyone.',
},
{
label: 'Can I use Pohon UI with Vue without Nuxt?',
icon: 'i-lucide:circle-help',
content: 'Yes! While optimized for Nuxt, Pohon UI works perfectly with standalone Vue projects via our Vite plugin. You can follow the [installation guide](/docs/pohon/getting-started/installation/vue) to get started.',
},
{
label: 'Will Pohon UI work with other CSS frameworks like Tailwind CSS?',
icon: 'i-lucide:circle-help',
content: 'No. Pohon UI is designed exclusively for UnoCSS. Tailwind CSS support would require significant architecture changes due to different class naming conventions.',
},
{
label: 'How does Pohon UI handle accessibility?',
icon: 'i-lucide:circle-help',
content: 'Through [Akar](/docs/akar/overview/accessibility) integration, Pohon 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 Pohon UI tested?',
icon: 'i-lucide:circle-help',
content: 'Pohon UI ensures reliability with 1000+ Vitest tests covering core functionality and accessibility.',
},
{
label: 'Is Pohon UI production-ready?',
icon: 'i-lucide:circle-help',
content: 'Yes! Pohon UI is used in production by thousands of applications with extensive tests, regular updates, and active maintenance.',
},
];
</script>
<template>
<PAccordion
type="multiple"
:items="items"
:unmount-on-hide="false"
:default-value="['3']"
:pohon="{
trigger: 'text-base',
body: 'text-base color-text-muted',
}"
>
<template #body="{ item }">
<MDC
:value="item.content"
unwrap="p"
/>
</template>
</PAccordion>
</template>
| Prop | Default | Type |
|---|
| Event | Type |
|---|
| Slot | Type |
|---|
Below is the theme configuration skeleton for the PAccordion. Since the component is provided unstyled by default, you will need to fill in these values to apply your own custom look and feel. If you prefer to use our pre-built, opinionated styling, you can instead use our UnoCSS preset, this docs is using it as well.
export default defineAppConfig({
pohon: {
accordion: {
slots: {
root: '',
item: '',
header: '',
trigger: '',
content: '',
body: '',
leadingIcon: '',
trailingIcon: '',
label: ''
},
variants: {
disabled: {
true: {
trigger: ''
}
}
},
compoundVariants: []
}
}
};
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pohon from 'pohon-ui/vite'
export default defineAppConfig({
pohon: {
accordion: {
slots: {
root: '',
item: '',
header: '',
trigger: '',
content: '',
body: '',
leadingIcon: '',
trailingIcon: '',
label: ''
},
variants: {
disabled: {
true: {
trigger: ''
}
}
},
compoundVariants: []
}
}
};
Here is the anatomy of themeable parts of the Accordion component:
Coming soon...
With Pohon UI, you can achieve similar component functionality with less code and effort, as it comes with built-in styles mechanism and behaviors that are optimized for common use cases. Since it's using unocss-variants it adds a runtime cost, but it can be worth it if you prioritize development speed and ease of use over fine-grained control.
If this is a deal breaker for you, you can always stick to using Akar and build your own custom components on top of it.