# @surdeddd/bottom-sheet · Svelte 5 Svelte 5 adapter. Ships `createBottomSheet()` — a rune-friendly controller factory you wire up via `$effect` and `bind:this`. The helper itself is plain TypeScript so it works under any Svelte 5 toolchain (Vite, SvelteKit, Astro) without extra build configuration. ## Install ```bash npm i @surdeddd/bottom-sheet svelte ``` ## Usage ```svelte

Search

Active: {activeId}

``` ## Controller API ```ts type SvelteBottomSheetController = { attach(refs: { element: HTMLElement; handle?: HTMLElement; scrollContainer?: HTMLElement; backdrop?: HTMLElement; screenComponent?: HTMLElement; }): () => void; // returns teardown state(): EngineState; // snapshot on(event, fn): () => void; // unsubscribe snapTo(id: string): Promise; open(id?: string): Promise; close(): Promise; setAllowed(ids: string[], snap?: string): void; destroy(): void; }; ``` ## SvelteKit / SSR `createBottomSheet()` does not touch the DOM. The engine attaches only when you call `ctrl.attach()` from inside `$effect` (which never runs on the server). SSR pages render the static HTML shell; gestures activate on the client after hydration. ## One-shot construction `createBottomSheet(opts)` snapshots `opts` at construction time. Reactive changes to `opts.snapPoints` / `opts.allowed` / `opts.mode` from the calling component DO NOT propagate to the engine — by design, to avoid silent reactivity bugs when callers pass non-reactive object literals. For runtime updates, use the controller methods: ```svelte ``` Engine recreation (changing `mode`, `animation`, `focusTrap`) requires calling `ctrl.destroy()` and constructing a fresh controller — the controller's `attach()` re-uses the constructor-time `opts` snapshot. ## Why a controller, not a `` component? Distributing a `.svelte` component would require shipping precompiled Svelte artifacts and a separate build pipeline. The controller pattern keeps the adapter framework-version-agnostic — it works under Svelte 5 today and stays forward-compatible as Svelte evolves runes API.