Accordion

AkarGitHub
A vertically stacked set of interactive headings that each reveal an associated section of content.

Usage

Use the Accordion component to display a list of collapsible items.

Yes. It adheres to the WAI-ARIA design pattern.
<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>

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
  • pohon?: { 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>

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 { 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>

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 { 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>

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 { 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>
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.

<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>

Trailing Icon

Use the trailing-icon prop to customize the trailing Icon of each item. Defaults to i-lucide:chevron-down.

You can also set an icon for a specific item by using the 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 customize this icon globally in your app.config.ts under pohon.icons.chevronDown key.
You can customize this icon globally in your vite.config.ts under pohon.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.

Yes. It adheres to the WAI-ARIA design pattern.
<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>
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 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>

With body slot

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>
The #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 { 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>

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 { 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>

With markdown content

You can use the MDC component from @nuxtjs/mdc to render markdown in the accordion items.

Through Akar 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.
<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>

API

Props

Prop Default Type

Emits

Event Type

Slots

Slot Type

Theme

We use unocss-variants to customize the theme. Read more about it in the theming guide.

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.

app.config.ts
export default defineAppConfig({
  pohon: {
    accordion: {
      slots: {
        root: '',
        item: '',
        header: '',
        trigger: '',
        content: '',
        body: '',
        leadingIcon: '',
        trailingIcon: '',
        label: ''
      },
      variants: {
        disabled: {
          true: {
            trigger: ''
          }
        }
      },
      compoundVariants: []
    }
  }
};
vite.config.ts
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: []
    }
  }
};

Anatomy

Here is the anatomy of themeable parts of the Accordion component:

Coming soon...

Akar

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.

Changelog

No recent changes