Accordion

Organizes content into collapsible sections, allowing users to focus on one section at a time.

	<script lang="ts">
  import { Accordion } from "bits-ui";
  import CaretDown from "phosphor-svelte/lib/CaretDown";
 
  const items = [
    {
      title: "What is the meaning of life?",
      content:
        "To become a better person, to help others, and to leave the world a better place than you found it."
    },
    {
      title: "How do I become a better person?",
      content:
        "Read books, listen to podcasts, and surround yourself with people who inspire you."
    },
    {
      title: "What is the best way to help others?",
      content: "Give them your time, attention, and love."
    }
  ];
 
  let value = $state<string[]>([]);
</script>
 
<Accordion.Root class="w-full sm:max-w-[70%]" type="multiple" bind:value>
  {#each items as item, i}
    <Accordion.Item value={`${i}`} class="group border-b border-dark-10 px-1.5">
      <Accordion.Header>
        <Accordion.Trigger
          class="flex w-full flex-1 items-center justify-between py-5 text-[15px] font-medium transition-all [&[data-state=open]>span>svg]:rotate-180"
        >
          {item.title}
          <span
            class="inline-flex size-8 items-center justify-center rounded-[7px] bg-transparent transition-all hover:bg-dark-10"
          >
            <CaretDown class="size-[18px] transition-all duration-200" />
          </span>
        </Accordion.Trigger>
      </Accordion.Header>
      <Accordion.Content
        class="overflow-hidden text-sm tracking-[-0.01em] data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
      >
        <div class="pb-[25px]">
          {item.content}
        </div>
      </Accordion.Content>
    </Accordion.Item>
  {/each}
</Accordion.Root>
	

Structure

	<script lang="ts">
	import { Accordion } from "bits-ui";
</script>
 
<Accordion.Root>
	<Accordion.Item>
		<Accordion.Header>
			<Accordion.Trigger />
		</Accordion.Header>
		<Accordion.Content />
	</Accordion.Item>
</Accordion.Root>
	

Usage

Single

Set the type prop to "single" to allow only one accordion item to be open at a time.

	<Accordion.Root type="single">
	<!-- ... -->
</Accordion.Root>
	

Multiple

Set the type prop to "multiple" to allow multiple accordion items to be open at the same time.

	<Accordion.Root type="multiple">
	<!-- ... -->
</Accordion.Root>
	

Disable Items

To disable an individual accordion item, set the disabled prop to true. This will prevent users from interacting with the item.

	<Accordion.Root type="single">
	<Accordion.Item value="item-1" disabled>
		<!-- ... -->
	</Accordion.Item>
</Accordion.Root>
	

Controlled Value

You can programmatically control the active of the accordion item(s) using the value prop.

	<script lang="ts">
	let value = $state("item-1");
</script>
 
<button onclick={() => (value = "item-2")}>Change value</button>
 
<Accordion.Root bind:value>
	<!-- ... -->
</Accordion.Root>
	

Value Change Side Effects

You can use the onValueChange prop to handle side effects when the value of the accordion changes.

	<Accordion.Root
	onValueChange={(value) => {
		doSomething(value);
	}}
>
	<!-- ... -->
</Accordion.Root>
	

Alternatively, you can use bind:value with an $effect block to handle side effects when the value of the accordion changes.

	<script lang="ts">
	import { Accordion } from "bits-ui";
 
	let value = $state("item-1")
 
	$effect(() => {
		doSomething(value);
	})
</script>
 
<Accordion.Root bind:value>
	<!-- ... -->
</Accordion.Item>
	

Reusable Wrappers

Entire Component

If you're going to be using the same accordion component multiple places throughout your app, you can create a reusable wrapper to reduce the amount of code you need to write each time.

CustomAccordion.svelte
	<script lang="ts">
	import { Accordion, type WithoutChildren } from "bits-ui";
 
	type Props = WithoutChildren<Accordion.RootProps> & {
		items: Array<{
			value: string;
			disabled?: boolean;
			title: string;
			content: string;
		}>;
	};
 
	let { items, value = $bindable(""), ...restProps }: Props = $props();
</script>
 
<Accordion.Root bind:value {...restProps}>
	{#each items as item}
		<Accordion.Item value={item.value} disabled={item.disabled}>
			<Accordion.Header>
				<Accordion.Trigger>{item.title}</Accordion.Trigger>
			</Accordion.Header>
			<Accordion.Content>{item.content}</Accordion.Content>
		</Accordion.Item>
	{/each}
</Accordion.Root>
	

Individual Item

For each invidual item, you need an Accordion.Item, Accordion.Header, Accordion.Trigger and Accordion.Content component. You can make a reusable wrapper to reduce the amount of code you need to write each time.

CustomAcccordionItem.svelte
	<script lang="ts">
	import { Accordion, type WithoutChildren } from "bits-ui";
 
	type Props = WithoutChildren<Accordion.ItemProps> & {
		title: string;
		content: string;
	};
 
	let { title, content, ...restProps }: Props = $props();
</script>
 
<Accordion.Item {...restProps}>
	<Accordion.Header>
		<Accordion.Trigger>
			{title}
		</Accordion.Trigger>
	</Accordion.Header>
	<Accordion.Content>
		{content}
	</Accordion.Content>
</Accordion.Item>
	
+page.svelte
	<script lang="ts">
	import { Accordion } from "bits-ui";
	import CustomAccordionItem from "$lib/components/CustomAccordionItem.svelte";
</script>
 
<Accordion.Root type="single">
	<CustomAccordionItem title="Item 1" content="Content 1" />
	<CustomAccordionItem title="Item 2" content="Content 2" />
	<CustomAccordionItem title="Item 3" content="Content 3" />
</Accordion.Root>
	

API Reference

Accordion.Root

The root accordion component used to set and manage the state of the accordion.

Property Type Description
multiple
boolean

Whether or not multiple accordion items can be active at the same time.

Default: false
disabled
boolean

Whether or not the accordion is disabled.

Default: false
value
union

The active accordion item value.

Default: undefined
onValueChange
function

A callback function called when the active accordion item value changes.

Default: undefined
asChild
boolean

Whether to use render delegation with this component or not.

Default: false
el
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to programatically interact with the element.

Default: undefined
Slot Property Type Description
builder
object

The builder attributes and actions to apply to the element if using the asChild prop with delegation.

Data Attribute Value Description
data-orientation
enum

The orientation of the accordion.

data-accordion-root

Present on the root element.

Accordion.Item

An accordion item.

Property Type Description
value
*
Required
string

The value of the accordion item.

Default: undefined
disabled
boolean

Whether or not the accordion item is disabled.

Default: false
asChild
boolean

Whether to use render delegation with this component or not.

Default: false
el
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to programatically interact with the element.

Default: undefined
Slot Property Type Description
builder
object

The builder attributes and actions to apply to the element if using the asChild prop with delegation.

Data Attribute Value Description
data-state
enum

The state of the accordion item.

data-disabled

Present when the accordion item is disabled.

data-accordion-item
——

Present on the item element.

Accordion.Header

The accordion item header, which wraps the trigger and makes it more accessible.

Property Type Description
level
enum

The heading level to use for the header. This will be set as the aria-level attribute.

Default: undefined
asChild
boolean

Whether to use render delegation with this component or not.

Default: false
el
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to programatically interact with the element.

Default: undefined
Slot Property Type Description
builder
object

The builder attributes and actions to apply to the element if using the asChild prop with delegation.

Data Attribute Value Description
data-heading-level
enum

The heading level of the header.

data-accordion-header
——

Present on the header element.

Accordion.Trigger

The accordion item trigger, which opens and closes the accordion item.

Property Type Description
asChild
boolean

Whether to use render delegation with this component or not.

Default: false
el
HTMLButtonElement

The underlying DOM element being rendered. You can bind to this to programatically interact with the element.

Default: undefined
Slot Property Type Description
builder
object

The builder attributes and actions to apply to the element if using the asChild prop with delegation.

Data Attribute Value Description
data-state
enum

The state of the accordion item.

data-disabled
——

Present when the accordion item is disabled.

data-value
——

The value of the accordion item.

data-accordion-trigger
——

Present on the trigger element.

Accordion.Content

The accordion item content, which is displayed when the item is open.

Property Type Description
transition
function

A Svelte transition function to use when transitioning the content in and out.

Default: undefined
transitionConfig
TransitionConfig

The configuration to apply to the transition.

Default: undefined
inTransition
function

A Svelte transition function to use when transitioning the content in and out.

Default: undefined
inTransitionConfig
TransitionConfig

The configuration to apply to the transition.

Default: undefined
outTransition
function

A Svelte transition function to use when transitioning the content in and out.

Default: undefined
outTransitionConfig
TransitionConfig

The configuration to apply to the transition.

Default: undefined
asChild
boolean

Whether to use render delegation with this component or not.

Default: false
el
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to programatically interact with the element.

Default: undefined
Slot Property Type Description
builder
object

The builder attributes and actions to apply to the element if using the asChild prop with delegation.

Data Attribute Value Description
data-state
enum

The state of the accordion item.

data-disabled
——

Present when the accordion item is disabled.

data-value
——

The value of the accordion item.

data-accordion-content
——

Present on the content element.