v0.0.14
builders

Floating builder

Builder class for creating accessible floating UI elements like tooltips and popovers. It connects triggers, content, and optional backdrops to a positioning engine while handling focus management, ARIA patterns, and common close behaviors (outside click, escape, scroll, resize).

Prerequisites

For the positioning to work correctly, the floating content element must use fixed positioning. Apply the following CSS to the content element:

position: fixed;
width: max-content;
top: 0;
left: 0;

Usage

<script>
    import { FloatingBuilder } from 'svxui';

    // Controlled open state
    let isOpen = $state(false);

    // Initialize floating
    const floating = new FloatingBuilder({
        get isOpen() {
            return isOpen;
        },
        set isOpen(value) {
            isOpen = value;
        },
        pattern: 'popover',
        closeOnOutsideClick: true,
        closeOnEscape: true
    });
</script>

<!-- Trigger element -->
<button {...floating.triggerAttrs} onclick={floating.toggle}>
    Open popover
</button>

<!-- Content element -->
{#if isOpen}
    <div {...floating.contentAttrs} class="popover">
        <p>This is a popover</p>
    </div>
{/if}

<style>
    .popover {
        /* Required styles */
        position: fixed;
        width: max-content;
        top: 0;
        left: 0;

        /* Others styles */
        z-index: 1;
        padding: 1rem;
        border-radius: 1rem;
        border: 1px solid light-dark(black, white);
        background-color: light-dark(white, black);
        color: light-dark(black, white);
    }
</style>

Type Definition

FloatingBuilder

export declare class FloatingBuilder {
    constructor(options: FloatingBuilderOptions);

    /**
     * Returns whether the floating element is currently open
     */
    get isOpen(): boolean;

    /**
     * Current computed floating engine state
     */
    get state(): any;

    /**
     * Open the floating element
     */
    open: () => boolean;

    /**
     * Close the floating element
     */
    close: () => boolean;

    /**
     * Toggle the open state
     */
    toggle: () => boolean;

    /**
     * Trigger attributes to spread on the trigger element
     */
    get triggerAttrs(): FloatingTriggerAttributes;

    /**
     * Backdrop attributes to spread on the backdrop element
     */
    get backdropAttrs(): FloatingBackdropAttributes;

    /**
     * Content element attributes
     */
    get contentAttrs(): FloatingContentAttributes;
}

FloatingBuilderOptions

import type {
    FloatingAlignment,
    FloatingEngineOptions,
    FloatingSide
} from '$lib/utilities/floating-engine/types.js';

export type FloatingBuilderOptions = {
    /**
     * Controls whether the floating element is open
     */
    isOpen: boolean;
    /**
     * Accessibility pattern to apply (tooltip or popover)
     */
    pattern?: 'tooltip' | 'popover';
    /**
     * Configuration options for the floating positioning engine
     */
    engineOptions?: FloatingEngineOptions | undefined;
    /**
     * Element to focus when the floating content opens
     */
    focusOnOpen?: HTMLElement | string | undefined;
    /**
     * Element to focus when the floating content closes
     */
    focusOnClose?: HTMLElement | string | undefined;
    /**
     * Whether to trap focus inside the floating content
     */
    focusTrap?: boolean | undefined;
    /**
     * Close when clicking on the backdrop
     */
    closeOnBackdropClick?: boolean;
    /**
     * Close when clicking outside the floating content
     */
    closeOnOutsideClick?: boolean;
    /**
     * Close when clicking the trigger element
     */
    closeOnClickTrigger?: boolean;
    /**
     * Close when pressing the Escape key
     */
    closeOnEscape?: boolean;
    /**
     * Close when the window is resized
     */
    closeOnResize?: boolean;
    /**
     * Close when the window or container is scrolled
     */
    closeOnScroll?: boolean;
};

/**
 * Floating trigger attributes
 */
export type FloatingTriggerAttributes = {
    readonly 'data-state': 'open' | 'closed';
    readonly [key: string]: unknown;
};

/**
 * Floating backdrop attributes
 */
export type FloatingBackdropAttributes = {
    readonly role: 'button';
    readonly tabindex: -1;
    readonly 'data-state': 'open' | 'closed';
};

/**
 * Floating content attributes
 */
export type FloatingContentAttributes = {
    readonly 'data-state': 'open' | 'closed';
    readonly 'data-side': FloatingSide | undefined;
    readonly 'data-align': FloatingAlignment | undefined;
    readonly style: string;
    readonly [key: string]: unknown;
};