v0.0.14
builders

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;
};