Accordion builder
Builder class for creating accessible Accordion components. Handles keyboard navigation, ARIA attributes, and panel toggling.
Usage
<script>
import { AccordionBuilder } from 'svxui';
// Controlled value state
let value: string[] = $state([]);
const options = ['Accordion1', 'Accordion2', 'Accordion3'];
// Initialize accordion
const accordion = new AccordionBuilder({
get value() {
return value;
},
set value(newValue) {
value = newValue;
}
});
</script>
<!-- Accordion container -->
<div class="accordion-root" {...accordion.rootAttrs}>
<!-- Accordion items -->
{#each options as opt, i (i)}
{@const item = accordion.getItem(opt)}
<div class="accordion" {...item.itemAttrs}>
<!-- Heading -->
<div class="heading" {...item.headingAttrs}>
Title {value}
<!-- Trigger -->
<button {...item.triggerAttrs}>
{item.expanded ? 'close' : 'open'}
</button>
</div>
<!-- Content -->
{#if item.expanded}
<div class="content" {...item.contentAttrs}>
Content {value}
</div>
{/if}
</div>
{/each}
</div>
<style>
.accordion-root {
display: flex;
flex-direction: column;
gap: 5px;
.accordion {
display: flex;
flex-direction: column;
border: 1px solid light-dark(black, white);
.heading {
padding: 1rem;
display: flex;
justify-content: space-between;
}
.content {
padding: 1rem;
}
}
}
</style>Type Definition
AccordionBuilder
export declare class AccordionBuilder<Value, Multiple extends boolean> {
/**
* @param options - Accordion configuration options.
*
* **Lifecycle note:** `AccordionBuilder` internally uses `SelectionState` which holds a reactive
* `$effect.root()`. Call `destroy()` when the builder is instantiated outside a Svelte component
* to avoid memory leaks.
*/
constructor(options: AccordionBuilderOptions<Value, Multiple>);
/**
* Accordion instance id
*/
get id(): string;
/**
* Can open single or multiple accordion items at a time
*/
get multiple(): boolean;
/**
* Accordion orientation
*/
get orientation(): Orientation;
/**
* Accordion is globally disabled
*/
get disabled(): boolean;
/**
* Check if an accordion item is expanded
* @param value The accordion item value to check
* @returns `true` if the item is currently expanded
*/
isExpanded: (value: Value) => boolean;
/**
* Expand an accordion item
* @param value The accordion item value to expand
*/
expand: (value: Value) => void;
/**
* Collapse an accordion item
* @param value The accordion item value to collapse
*/
collapse: (value: Value) => void;
/**
* Toggle expand/collapse an accordion item
* @param value The accordion item value to toggle
*/
toggle: (value: Value) => void;
/**
* Destroy internal reactive effects. Call this when the builder is instantiated
* outside a Svelte component to avoid memory leaks.
*/
destroy: () => void;
/**
* Accordion root attributes
*/
get rootAttrs(): AccordionRootAttributes;
/**
* Build an accordion item state
* @param value The accordion item value
* @param itemOptions Optional per-item configuration overrides
* @returns The accordion item instance
*/
getItem: (value: Value, itemOptions?: AccordionItemOptions) => AccordionItem;
}AccordionBuilderOptions
import type { Orientation } from '$lib/shared.types.js';
import type { SelectionStateOptions } from '$lib/utilities/selection-state/index.js';
export type AccordionHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
/**
* Accordion builder options
*
* @template Value - Value of single or multiple selection.
* @template Multiple - Boolean indicating if multiple selection is enabled.
*/
export type AccordionBuilderOptions<Value, Multiple extends boolean> = SelectionStateOptions<
Value,
Multiple
> & {
/**
* Accordion orientation
*/
orientation?: Orientation;
/**
* Accordion must be disabled or not
*/
disabled?: boolean;
};
/**
* Accordion item customization
*/
export type AccordionItemOptions = {
/**
* Custom accordion item id
*/
id?: string;
/**
* Disable or not accordion item
*/
disabled?: boolean;
/**
* Custom accordion item heading level
*/
headingLevel?: AccordionHeadingLevel;
};
/**
* Accordion item state
*/
export type AccordionItem = {
/**
* Accordion item is expanded
*/
readonly expanded: boolean;
/**
* Accordion item is disabled
*/
readonly disabled: boolean;
/**
* Accordion item wrapper attributes
*/
readonly itemAttrs: AccordionItemAttributes;
/**
* Accordion item heading attributes
*/
readonly headingAttrs: AccordionHeadingAttributes;
/**
* Accordion item trigger attributes
*/
readonly triggerAttrs: AccordionTriggerAttributes;
/**
* Accordion item content attributes
*/
readonly contentAttrs: AccordionContentAttributes;
};
export type AccordionRootAttributes = {
readonly id: string;
readonly tabindex: number;
readonly 'data-disabled': string | undefined;
readonly 'data-orientation': Orientation;
};
export type AccordionItemAttributes = {
readonly id: string;
readonly 'data-state': string;
readonly 'data-disabled'?: string;
readonly 'data-orientation': Orientation;
};
export type AccordionHeadingAttributes = {
readonly id: string;
readonly 'data-state': string;
readonly 'data-disabled'?: string;
readonly 'data-orientation': Orientation;
readonly 'data-heading-level'?: AccordionHeadingLevel;
readonly 'aria-level'?: AccordionHeadingLevel;
readonly role: string;
};
export type AccordionTriggerAttributes = {
readonly id: string;
readonly tabindex: number;
readonly disabled: boolean;
readonly 'data-state': string;
readonly 'data-disabled': string | undefined;
readonly 'data-orientation': Orientation;
readonly 'aria-disabled': boolean | undefined;
readonly 'aria-expanded': boolean;
readonly 'aria-controls': string;
readonly onclick: (e: MouseEvent) => void;
};
export type AccordionContentAttributes = {
readonly id: string;
readonly role: string;
readonly 'data-state': string;
readonly 'data-disabled': string | undefined;
readonly 'data-orientation': Orientation;
readonly 'aria-labelledby': string;
};