Tabs builder
Builder class for creating accessible Tabs components. Handles focus management, keyboard interactions, and ARIA attributes.
Usage
<script>
import { TabsBuilder } from 'svxui/builders/tabs';
// Controlled value state
let value = $state('Tab1');
const options = ['Tab1', 'Tab2', 'Tab3'];
// Initialize tabs
const tabs = new TabsBuilder({
get value() {
return value;
},
set value(newValue) {
value = newValue;
},
orientation: 'horizontal',
activateOnFocus: true,
loop: true
});
</script>
<!-- Tabs container -->
<div class="tabs" {...tabs.rootAttrs}>
<!-- Tabs triggers container -->
<div class="triggers" {...tabs.triggerListAttrs}>
{#each options as opt, i (i)}
{@const trigger = tabs.getTrigger(opt)}
<button class="trigger" class:active={trigger.active} {...trigger.attrs}>{opt}</button>
{/each}
</div>
<!-- Tabs contents -->
{#each options as opt, i (i)}
{@const content = tabs.getContent(opt)}
{#if content.active}
<div class="content" {...content.attrs}>{opt}</div>
{/if}
{/each}
</div>
<style>
.tabs {
display: flex;
flex-direction: column;
gap: 5px;
.triggers {
display: flex;
gap: 5px;
.trigger.active {
background-color: lightgray;
color: black;
}
}
.content {
padding: 1rem;
}
}
</style>Type Definition
TabsBuilder
export declare class TabsBuilder<Value> {
/**
* @param options - Tabs configuration options.
*
* **Lifecycle note:** `TabsBuilder` 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: TabsBuilderOptions<Value>);
/**
* Tabs instance id
*/
get id(): string;
/**
* Tabs orientation
*/
get orientation(): Orientation;
/**
* Tabs is globally disabled
*/
get disabled(): boolean;
/**
* Loop or not keyboard navigation
*/
get loop(): boolean;
/**
* Enable or not tab activation on focus
*/
get activateOnFocus(): boolean;
/**
* Check if an tab item is active
* @param value The tab item value to check
*/
isActive: (value: Value) => boolean;
/**
* Activate a tab item
* @param value The tab item value to activate
*/
activate: (value: Value) => void;
/**
* Destroy internal reactive effects. Call this when the builder is instantiated
* outside a Svelte component to avoid memory leaks.
*/
destroy: () => void;
/**
* Tabs root attributes
*/
get rootAttrs(): TabsRootAttributes;
/**
* Tabs triggers list attributes
*/
get triggerListAttrs(): TabsItemTriggerListAttributes;
/**
* Build a tab item trigger part
* @param value The tab item value
* @param triggerOptions Optional per-trigger configuration overrides
* @returns The tabs item trigger instance
*/
getTrigger(value: Value, triggerOptions?: TabsItemTriggerOptions): TabsItemTrigger;
/**
* Build a tab item content part
* @param value The tab item value
* @param contentOptions Optional per-content configuration overrides
* @returns The tabs item content instance
*/
getContent(value: Value, contentOptions?: TabsItemContentOptions): TabsItemContent;
}TabsBuilderOptions
import type { Orientation } from '$lib/shared.types.js';
import type { SelectionStateOptions } from '$lib/utilities/selection-state/index.js';
/**
* Tabs state options
*/
export type TabsBuilderOptions<Value> = Omit<SelectionStateOptions<Value, false>, 'multiple'> & {
/**
* Tabs orientation
*/
orientation?: Orientation;
/**
* Tabs must be disabled or not
*/
disabled?: boolean;
/**
* Loop focus on keyboard navigation
*/
loop?: boolean;
/**
* Activate item on focus
*/
activateOnFocus?: boolean;
};
export type TabsRootAttributes = {
readonly id: `tabs-root-${string}`;
readonly 'data-disabled': '' | undefined;
readonly 'data-orientation': Orientation;
};
export type TabsItemTriggerListAttributes = {
readonly [x: string]: '' | Orientation | `tabs-list-${string}` | 'tablist' | undefined;
readonly id: `tabs-list-${string}`;
readonly 'data-disabled': '' | undefined;
readonly 'data-orientation': Orientation;
readonly role: 'tablist';
};
/**
* Tabs item trigger part customization
*/
export type TabsItemTriggerOptions = {
/**
* Custom tab item triggert part id
*/
id?: string;
/**
* Disable or not tab item
*/
disabled?: boolean;
};
/**
* Tabs item trigger part state
*/
export type TabsItemTrigger = {
/**
* Tab item is activated or not
*/
readonly active: boolean;
/**
* Tab item is disabled or not
*/
readonly disabled?: boolean;
/**
* Tab trigger part attributes
*/
readonly attrs: TabsItemTriggerAttributes;
};
export type TabsItemTriggerAttributes = {
readonly id: string;
readonly tabindex: 0 | -1;
readonly disabled: boolean;
readonly 'data-state': 'active' | 'inactive';
readonly 'data-orientation': Orientation;
readonly 'data-disabled': '' | undefined;
readonly role: 'tab';
readonly 'aria-selected'?: boolean;
readonly 'aria-controls': string | undefined;
readonly onfocus: () => void;
readonly onclick: (e: MouseEvent) => void;
// readonly onkeydown: (e: KeyboardEvent) => void;
};
/**
* Tabs item content part customization
*/
export type TabsItemContentOptions = {
/**
* Custom tab item content part id
*/
id?: string;
/**
* Disable or not tab item
*/
disabled?: boolean;
};
/**
* Tab item content part state
*/
export type TabsItemContent = {
/**
* Tab item is activated or not
*/
readonly active: boolean;
/**
* Tab item is disabled or not
*/
readonly disabled?: boolean;
/**
* Tab content part attributes
*/
readonly attrs: TabsItemContentAttributes;
};
export type TabsItemContentAttributes = {
readonly id: string;
readonly disabled: boolean;
readonly tabindex: 0;
readonly hidden: true | undefined;
readonly 'data-state': 'active' | 'inactive';
readonly 'data-orientation': Orientation;
readonly 'data-disabled'?: '';
readonly role: 'tabpanel';
readonly 'aria-labelledby'?: string;
};