Listbox builder
Builder class for creating accessible Listbox components. Manages focus, selection state, keyboard interactions, and ARIA roles.
Usage
<script>
import { ListboxBuilder } from 'svxui';
// Controlled value state
let value = $state([]);
const options = ['option1', 'option2', 'option3'];
// Initialize listbox
const listbox = new ListboxBuilder({
get value() {
return value;
},
set value(newValue) {
value = newValue;
},
multiple: true,
loop: true
});
</script>
<!-- Listbox container -->
<div class="listbox" {...listbox.rootAttrs}>
<!-- Listbox items -->
{#each options as opt, i (i)}
{@const item = listbox.getItem(opt)}
<button {...item.attrs}>{opt}</button>
{/each}
</div>
<style>
.listbox {
display: flex;
flex-direction: column;
width: 220px;
gap: 5px;
button[data-state='selected'] {
background-color: lightgray;
color: black;
}
}
</style>Type Definition
ListboxBuilder
export declare class ListboxBuilder<Value, Multiple extends boolean> {
/**
* @param options - Listbox configuration options.
*
* **Lifecycle note:** `ListboxBuilder` 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: ListboxBuilderOptions<Value, Multiple>);
/**
* Listbox instance id
*/
get id(): string;
/**
* Can select single or multiple listbox item at time
*/
get multiple(): boolean;
/**
* Listbox orientation
*/
get orientation(): Orientation;
/**
* Listbox is globally disabled
*/
get disabled(): boolean;
/**
* Loop or not keyboard navigation
*/
get loop(): boolean;
/**
* Select item or not on focus
*/
get activateOnFocus(): boolean;
/**
* Check if item is selected or not
* @param value The item value to check
*/
isSelected: (value: Value) => boolean;
/**
* Select listbox item
* @param value The item value to select
*/
select: (value: Value) => void;
/**
* Deselect listbox item
* @param value The item value to deselect
*/
deselect: (value: Value) => void;
/**
* Toggle select/deselect item
* @param value The 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;
/**
* Listbox root element attributes
*/
get rootAttrs(): ListboxRootAttributes;
/**
* Build listbox item state
* @param value The item value
* @param options Optional per-item configuration overrides
* @returns The listbox item instance
*/
getItem: (value: Value, options?: ListboxItemOptions) => ListboxItem;
}ListboxBuilderOptions
import type { Orientation } from '$lib/shared.types.js';
import type { SelectionStateOptions } from '$lib/utilities/selection-state/index.js';
/**
* Listbox builder options
*/
export type ListboxBuilderOptions<Value, Multiple extends boolean> = SelectionStateOptions<
Value,
Multiple
> & {
/**
* Listbox orientation
*/
orientation?: Orientation;
/**
* Listbox must be disabled or not
*/
disabled?: boolean;
/**
* Loop focus on keyboard navigation
*/
loop?: boolean;
/**
* Activate item on focus
*/
activateOnFocus?: boolean;
};
/**
* Listbox item customization
*/
export type ListboxItemOptions = {
/**
* Custom listbox item id
*/
id?: string;
/**
* Disable or not listbox item
*/
disabled?: boolean;
};
/**
* Listbox item state
*/
export type ListboxItem = {
/**
* Listbox item is expanded
*/
readonly selected: boolean;
/**
* Listbox item is disabled
*/
readonly disabled: boolean;
/**
* Listbox item attributes
*/
readonly attrs: ListboxItemAttributes;
};
export type ListboxRootAttributes = {
readonly id: string;
readonly 'data-disabled': string | undefined;
readonly 'data-orientation': Orientation;
readonly tabindex: number;
readonly role: string;
readonly 'aria-multiselectable': boolean;
};
export type ListboxItemAttributes = {
readonly id: string;
readonly 'data-state': 'selected' | 'unselected';
readonly 'data-disabled'?: string;
readonly 'data-orientation': Orientation;
readonly tabindex: number;
readonly role: string;
readonly 'aria-selected'?: boolean;
readonly 'aria-disabled': boolean;
readonly disabled: boolean;
onclick: (event: MouseEvent) => void;
};