Accordion

An interactive component that enables the organization and navigation of content by allowing users to expand and collapse sections.

A collection of accessible & unstyled component builders for Svelte applications.

Features

  • Full keyboard navigation
  • Can expand one or multiple items
  • Can be controlled or uncontrolled

Anatomy

  • Root: The root container for the accordion
  • Item: The container for each accordion item
    • Header: The header for the accordion trigger
      • Trigger: The trigger for the accordion item
    • Content: The content area that is revealed when the trigger is clicked

Usage

To create an accordion, use the createAccordion builder function. Follow the anatomy or the example at the top of this page to create your accordion.

Disabling a single item

To disable a single item, you can pass in an object instead of a string to the function.

    <div class="accordion-item" use:melt={$item({ value: 'item-3', disabled: true })}>Item 3</div>
	
    <div class="accordion-item" {...$item({ value: 'item-3', disabled: true })} use:item>Item 3</div>
	

Opening multiple items at once

Pass in the multiple prop to createAccordion with a value of true.

    <script lang="ts">
  const { /* ... */ } = createAccordion({
  multiple: true
  })
	
    <script lang="ts">
  const { /* ... */ } = createAccordion({
  multiple: true
  })
	

Controlled

To programatically control the Accordion, you can Bring Your Own Store , or directly set the value store that's returned. You can also update any of the returned option stores to update the behavior of the Accordion.

    <script lang="ts">
  import { createAccordion, melt } from '@melt-ui/svelte'
  import { writable } from 'svelte/store'
 
  const customValue = writable('item-1')
 
  const {
    elements: { content, item, trigger, root },
    options: { disabled },
    states: { value }
  } = createAccordion({
    value: customValue
  })
</script>
 
<button
  on:click={() => {
    const randPick = Math.floor(Math.random() * 3) + 1
    customValue.set(`item-${randPick}`)
    // Alternatively, you can use the value store directly value.set(`item-${randPick}`)
  }}>
  Trigger randomly
</button>
 
<p>Value: {$value}</p>
 
<div use:melt={$root}>
  <div use:melt={$item('item-1')}>
    <button use:melt={$trigger('item-1')}>Is it accessible?</button>
    <div use:melt={$content('item-1')}>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
 
  <div use:melt={$item('item-2')}>
    <button use:melt={$trigger('item-2')}>Is it accessible?</button>
    <div use:melt={$content('item-2')}>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
 
  <div use:melt={$item('item-3')}>
    <button use:melt={$trigger('item-3')}>Is it accessible?</button>
    <div use:melt={$content('item-3')}>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
</div>
	
    <script lang="ts">
  import { createAccordion, melt } from '@melt-ui/svelte'
  import { writable } from 'svelte/store'
 
  const customValue = writable('item-1')
 
  const {
    elements: { content, item, trigger, root },
    options: { disabled },
    states: { value }
  } = createAccordion({
    value: customValue
  })
</script>
 
<button
  on:click={() => {
    const randPick = Math.floor(Math.random() * 3) + 1
    customValue.set(`item-${randPick}`)
    // Alternatively, you can use the value store directly value.set(`item-${randPick}`)
  }}>
  Trigger randomly
</button>
 
<p>Value: {$value}</p>
 
<div {...$root} use:root>
  <div {...$item('item-1')} use:item>
    <button {...$trigger('item-1')} use:trigger>Is it accessible?</button>
    <div {...$content('item-1')} use:content>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
 
  <div {...$item('item-2')} use:item>
    <button {...$trigger('item-2')} use:trigger>Is it accessible?</button>
    <div {...$content('item-2')} use:content>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
 
  <div {...$item('item-3')} use:item>
    <button {...$trigger('item-3')} use:trigger>Is it accessible?</button>
    <div {...$content('item-3')} use:content>
      <div>Yes. It adheres to the WAI-ARIA design pattern.</div>
    </div>
  </div>
</div>
	

API Reference

createAccordion

The builder function used to create the accordion component.

Props

Prop Default Type / Description
multiple false
boolean

If true, multiple accordion items can be open at the same time.

disabled false
boolean

Whether or not the accordion is disabled.

forceVisible false
boolean

Whether or not to force the accordion to always be visible. This is useful for custom transitions and animations using conditional blocks.

multiple false
boolean

If true, multiple accordion items can be open at the same time.

disabled false
boolean

Whether or not the accordion is disabled.

defaultValue -
string | string[] | undefined

The default value of the accordion.

value -
Writable<string | string[] | undefined>

A writable store that controls the value of the accordion. If provided, this will override the value passed to defaultValue.

See Bring Your Own Store

onValueChange -
ChangeFn<string | string[] | undefined>

A callback called when the value of the value store should be changed. This is useful for controlling the value of the accordion from outside the accordion.

See Change Functions

Elements

Element Description

The builder store used to create the accordion root.

The builder store used to create accordion items.

The builder store used to create accordion triggers.

The builder store used to create accordion content.

The builder store used to create accordion headings.

States

State Description
value

A writable store with the value of the currently open item.

Helpers

Helper Description
isSelected

A derived store that takes an item ID as an argument and returns whether or not the item is selected.

Options

Option Description
multiple

If true, multiple accordion items can be open at the same time.

disabled

Whether or not the accordion is disabled.

forceVisible

Whether or not to force the accordion to always be visible. This is useful for custom transitions and animations using conditional blocks.

root

Contains all the parts of an accordion.

Data Attributes

Data Attribute Value
[data-orientation]

'vertical' | 'horizontal'

[data-melt-accordion]

Present on all accordion root elements.

trigger

Toggles the collapsed state of an item. It should be nested inside of its associated item.

Props

Prop Default Type / Description
disabled false
boolean

Whether or not the trigger is disabled.

value -
string | string[] | undefined

The value of the associated accordion item.

Data Attributes

Data Attribute Value
[data-disabled]

Present when the trigger is disabled.

[data-value]

The value of the associated item.

[data-state]

'open' | 'closed'

[data-melt-accordion-trigger]

Present on all accordion trigger elements.

Custom Events

Event Value
m-keydown (e: ) => void
m-click (e: ) => void

item

Contains all the parts of a collapsible section.

Props

Prop Default Type / Description
value -
string
disabled false
boolean

Data Attributes

Data Attribute Value
[data-state]

'open' | 'closed'

[data-disabled]

Present when the item is disabled.

[data-melt-accordion-item]

Present on all accordion item elements.

content

Contains the collapsible content for an accordion item.

Props

Prop Default Type / Description
value -
string

The value of associated accordion item.

disabled false
boolean

Whether or not the content is disabled.

Data Attributes

Data Attribute Value
[data-state]

'open' | 'closed'

[data-disabled]

Present when the content is disabled.

[data-value]

The value of the associated item

[data-melt-accordion-content]

Present on all accordion content elements.

heading

The heading for an accordion item. It should be nested inside of its associated item.

Props

Prop Default Type / Description
level -
1 | 2 | 3 | 4 | 5 | 6

The heading level to use for the element.

Data Attributes

Data Attribute Value
[data-heading-level]

The heading level applied to the element.

[data-melt-accordion-heading]

Present on all accordion heading elements.

Accessibility

Adheres to the Accordion WAI-ARIA design pattern

Ensuring items are accessible

The easy way to ensure your accordion items are accessible is to wrap each trigger element in a heading element, like so:

    <h2>
  <button use:melt={$trigger(id)}>
    {title}
  </button>
</h2>
	
    <h2>
  <button {...$trigger(id)} use:trigger>
    {title}
  </button>
</h2>
	

However, there may be times when you can't use or don't want to use a heading element. In those cases, use the heading builder to apply the necessary aria attributes to the element. The argument passed to the heading builder is the heading level you wish to use. In the example below, we set the heading level to 4.

    <script lang="ts">
  const {
    elements: { root, content, item, trigger, heading }
  } = createAccordion()
</script>
	
    <script lang="ts">
  const {
    elements: { root, content, item, trigger, heading }
  } = createAccordion()
</script>
	
    <span use:melt={$heading(4)}>
  <button use:melt={$trigger(id)}>
    {title}
  </button>
<span>
	
    <span {...$heading(4)} use:heading>
  <button {...$trigger(id)} use:trigger>
    {title}
  </button>
<span>
	
Key Behavior
Space

When the trigger of a collapsed section is focused, expands the section.

Enter

When the trigger of a collapsed section is focused, expands the section.

Tab

Moves focus to the next focusable element.

Shift + Tab

Moves focus to the previous focusable element

ArrowDown

Moves focus to the next trigger element.

ArrowUp

Moves focus to the previous trigger element.

Home

When focus is on a trigger, moves focus to the first trigger.

End

When focus is on a trigger, moves focus to the last trigger.