Skip to content
Destyler UI Destyler UI Destyler UI

Collapse

An collapse is a vertically stacked set of interactive headings containing a title, content snippet, or thumbnail representing a section of content.

Features

Install

Install the component from your command line.

Terminal window
      
        
npm install @destyler/collapse @destyler/vue
Terminal window
      
        
npm install @destyler/collapse @destyler/react
Terminal window
      
        
npm install @destyler/collapse @destyler/svelte
Terminal window
      
        
npm install @destyler/collapse @destyler/solid

Anatomy

Import all parts and piece them together.

<script setup lang="ts">
import * as collapse from '@destyler/collapse'
import { normalizeProps, useMachine } from '@destyler/vue'
import { computed, useId } from 'vue'
const data = [ ... ]
const [state, send] = useMachine(collapse.machine({ id: useId() }))
const api = computed(() =>
collapse.connect(state.value, send, normalizeProps),
)
</script>
<template>
<div v-bind="api.getRootProps()">
<div
v-for="item in data"
:key="item.title"
v-bind="api.getItemProps({ value: item.title })"
>
<button v-bind="api.getItemTriggerProps({ value: item.title })"></button>
<div v-bind="api.getItemContentProps({ value: item.title })"></div>
</div>
</div>
</template>
import * as collapse from '@destyler/collapse'
import { normalizeProps, useMachine } from '@destyler/react'
import { useId } from 'react'
const data = [ ... ]
export default function Collapse() {
const [state, send] = useMachine(collapse.machine({ id: useId() }))
const api = collapse.connect(state, send, normalizeProps)
return (
<div {...api.getRootProps()}>
{data.map(item => (
<div key={item.title} {...api.getItemProps({ value: item.title })}>
<button {...api.getItemTriggerProps({ value: item.title })}></button>
<div {...api.getItemContentProps({ value: item.title })}></div>
</div>
))}
</div>
)
}
<script lang="ts">
import * as collapse from '@destyler/collapse'
import { normalizeProps, useMachine } from '@destyler/svelte'
const data = [ ... ]
const id = $props.id()
const [state, send] = useMachine(collapse.machine({ id }))
const api = $derived(collapse.connect(state, send, normalizeProps))
</script>
<div {...api.getRootProps()}>
{#each data as item (item.title)}
<div {...api.getItemProps({ value: item.title })}>
<button {...api.getItemTriggerProps({ value: item.title })}></button>
<div {...api.getItemContentProps({ value: item.title })}></div>
</div>
{/each}
</div>
import * as collapse from '@destyler/collapse'
import { normalizeProps, useMachine } from '@destyler/solid'
import { createUniqueId } from 'solid-js'
const data = [ ... ]
export default function Collapse() {
const [state, send] = useMachine(collapse.machine({ id: createUniqueId() }))
const api = collapse.connect(state, send, normalizeProps)
return (
<div {...api.getRootProps()}>
{data.map(item => (
<div {...api.getItemProps({ value: item.title })}>
<button {...api.getItemTriggerProps({ value: item.title })} ></button>
<div {...api.getItemContentProps({ value: item.title })}></div>
</div>
))}
</div>
)
}

Open multiple collapse at once

To allow multiple items to be expanded at once, set multiple to true. This mode implicitly sets collapsible to true and ensures that each collapse can be expanded.

const [state, send] = useMachine(
collapse.machine({
multiple: true,
}),
)

Opening specific collapse

To set the value of the collapse that should be opened initially, pass the value property to the machine function.

const [state, send] = useMachine(
collapse.machine({
multiple: true,
value: ["home"],
}),
)

Toggle each collapse item

To collapse an already expanded collapse item by clicking on it, set the context’s collapsible property to true.

const [state, send] = useMachine(
collapse.machine({
collapsible: true,
}),
)

Listening for changes

When the collapse value changes, the onValueChange callback is invoked.

const [state, send] = useMachine(
collapse.machine({
onValueChange(details) {
// details => { value: string[] }
console.log("selected collapse:", details.value)
},
}),
)

Disabling an collapse item

To disable a specific collapse item, pass the disabled: true property to the getItemProps, getItemTriggerProps and getItemContentProps.

When an collapse item is disabled, it is skipped from keyboard navigation and can’t be interacted with.

<template>
<!-- ... -->
<div v-bind="api.getItemProps({ value: 'item-1', disabled: true })">
<button v-bind="api.getItemTriggerProps({ value: 'item-1', disabled: true })"></button>
<div v-bind="api.getItemContentProps({ value: 'item-1', disabled: true })"></div>
</div>
<!-- ... -->
</template>
export default function Collapse() {
return (
// ...
<div {...api.getItemProps({ value: 'item-1', disabled: true })}>
<button {...api.getItemTriggerProps({ value: 'item-1', disabled: true })}></button>
<div {...api.getItemContentProps({ value: 'item-1', disabled: true })}></div>
</div>
// ...
)
}
<!-- ... -->
<div {...api.getItemProps({ value: 'item-1', disabled: true })}>
<button {...api.getItemTriggerProps({ value: 'item-1', disabled: true })}></button>
<div {...api.getItemContentProps({ value: 'item-1', disabled: true })}></div>
</div>
<!-- ... -->
export default function Collapse() {
return (
// ...
<div {...api.getItemProps({ value: 'item-1', disabled: true })}>
<button {...api.getItemTriggerProps({ value: 'item-1', disabled: true })} ></button>
<div {...api.getItemContentProps({ value: 'item-1', disabled: true })}></div>
</div>
// ...
)
}

You can also disable the entire collapse items by passing disabled to the machine’s context.

const [state, send] = useMachine(
collapse.machine({
disabled: true,
}),
)

Styling Guide

Earlier, we mentioned that each collapse part has a data-part attribute added to them to select and style them in the DOM.

Open and closed state

When an collapse item is expanded or collapsed, a data-state attribute is set on the item, trigger and content elements. This attribute is removed when it is closed.

[data-part="item"][data-state="open"] {
/* styles for the item is open or closed state */
}
[data-part="item-trigger"][data-state="open"] {
/* styles for the item is open or closed state */
}
[data-part="item-content"][data-state="open"] {
/* styles for the item is open or closed state */
}

Focused state

When an collapse item’s trigger is focused, a data-focus attribute is set on the item and content.

[data-part="item"][data-focus] {
/* styles for the item's focus state */
}
[data-part="item-trigger"]:focus {
/* styles for the trigger's focus state */
}
[data-part="item-content"][data-focus] {
/* styles for the content's focus state */
}

Methods and Properties

Machine Context

The collapse machine exposes the following context properties:

ids
Partial<{ root: string; item(value: string): string; itemContent(value: string): string; itemTrigger(value: string): string; }>
The ids of the elements in the collapse. Useful for composition.
multiple
boolean
Whether multiple collapse items can be expanded at the same time.
collapsible
boolean
Whether an collapse item can be closed after it has been expanded.
value
string[]
The `value` of the collapse items that are currently being expanded.
disabled
boolean
Whether the collapse items are disabled
onValueChange
(details: ValueChangeDetails) => void
The callback fired when the state of expanded/collapsed collapse items changes.
onFocusChange
(details: FocusChangeDetails) => void
The callback fired when the focused collapse item changes.
orientation
"horizontal" | "vertical"
The orientation of the collapse items.
dir
"ltr" | "rtl"
The document's text/writing direction.
id
string
The unique identifier of the machine.
getRootNode
() => ShadowRoot | Node | Document
A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The collapse api exposes the following methods:

focusedValue
string
The value of the focused collapse item.
value
string[]
The value of the collapse
setValue
(value: string[]) => void
Sets the value of the collapse.
getItemState
(props: ItemProps) => ItemState
Gets the state of an collapse item.

Data Attributes

Root

name
desc
data-scope
collapse
data-part
root
data-orientation
The orientation of the collapse

Item

name
desc
data-scope
collapse
data-part
item
data-state
"open" | "closed"
data-focus
Present when focused
data-disabled
Present when disabled
data-orientation
The orientation of the item

ItemContent

name
desc
data-scope
collapse
data-part
item-content
data-state
"open" | "closed"
data-disabled
Present when disabled
data-focus
Present when focused
data-orientation
The orientation of the item

ItemIndicator

name
desc
data-scope
collapse
data-part
item-indicator
data-state
"open" | "closed"
data-disabled
Present when disabled
data-focus
Present when focused
data-orientation
The orientation of the item

ItemTrigger

name
desc
data-scope
collapse
data-part
item-trigger
data-orientation
The orientation of the item
data-state
"open" | "closed"

Accessibility

Keyboard Interaction

name
desc
Space
When focus is on an trigger of a collapsed item, the item is expanded
Enter
When focus is on an trigger of a collapsed section, 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
ArrowUp
Moves focus to the previous trigger.
Home
When focus is on an trigger, moves focus to the first trigger.
End
When focus is on an trigger, moves focus to the last trigger.