Spec Registry
Help your agents use open-source better. Learn more.
Find usage specs for your project’s dependencies
- Author
- tessl
- Last updated
- Spec files
npm-svelte
Describes: npm/svelte
- Description
- A cybernetically enhanced web application framework that compiles to highly optimized JavaScript with reactive state management and component-based architecture.
- Author
- tessl
- Last updated
reactivity.md docs/
1# Reactivity Control23Svelte provides functions for controlling reactive updates, managing execution timing, handling asynchronous operations, and reactive versions of built-in JavaScript objects for comprehensive reactivity.45## Capabilities67### tick89Returns a Promise that resolves after any pending state changes have been applied to the DOM.1011```typescript { .api }12/**13* Returns a promise that resolves once any pending state changes have been applied14* @returns Promise that resolves after DOM updates15*/16function tick(): Promise<void>;17```1819**Usage Examples:**2021```typescript22import { tick } from "svelte";2324let count = $state(0);25let element;2627async function updateAndRead() {28count += 1;2930// Wait for DOM to update31await tick();3233// Now we can safely read the updated DOM34console.log("Updated element text:", element.textContent);35}3637// Measuring DOM changes38async function measureHeight(newContent) {39const oldHeight = element.offsetHeight;4041// Update content42content = newContent;4344// Wait for DOM update45await tick();4647const newHeight = element.offsetHeight;48console.log(`Height changed from ${oldHeight} to ${newHeight}`);49}5051// Focusing elements after conditional rendering52let showInput = $state(false);53let inputElement;5455async function showAndFocus() {56showInput = true;5758// Wait for input to be rendered59await tick();6061// Now we can focus it62inputElement?.focus();63}64```6566### settled6768Returns a Promise that resolves when all async state updates have completed. More comprehensive than `tick()` for complex reactive chains.6970```typescript { .api }71/**72* Returns a promise that resolves when all reactive updates have settled73* @returns Promise that resolves after all async updates74*/75function settled(): Promise<void>;76```7778**Usage Examples:**7980```typescript81import { settled } from "svelte";8283let loading = $state(false);84let data = $state([]);85let processedData = $state([]);8687// Derived values that might trigger additional updates88let filteredData = $derived(data.filter(item => item.active));89let sortedData = $derived(filteredData.sort((a, b) => a.name.localeCompare(b.name)));9091async function loadAndProcess() {92loading = true;9394// Fetch data95const response = await fetch("/api/data");96data = await response.json();9798// Wait for all reactive updates to settle99await settled();100101// Now all derived values are up to date102console.log("Final processed data:", sortedData);103loading = false;104}105106// Complex reactive chains107let userInput = $state("");108let searchResults = $state([]);109let selectedItems = $state([]);110111$effect(async () => {112if (userInput.length > 2) {113searchResults = await searchAPI(userInput);114}115});116117async function processSelection() {118// Update multiple reactive values119selectedItems = [...selectedItems, ...searchResults.slice(0, 3)];120userInput = "";121122// Wait for all reactive updates to complete123await settled();124125// Safe to perform operations that depend on final state126saveSelections(selectedItems);127}128```129130### untrack131132Executes a function without creating reactive dependencies or triggering reactive updates.133134```typescript { .api }135/**136* Run a function without creating dependencies on reactive state137* @param fn - Function to run without tracking138* @returns Return value of the function139*/140function untrack<T>(fn: () => T): T;141```142143**Usage Examples:**144145```typescript146import { untrack } from "svelte";147148let count = $state(0);149let lastUpdate = $state(Date.now());150151// Effect that doesn't depend on lastUpdate changes152$effect(() => {153console.log(`Count is ${count}`);154155// Update timestamp without creating dependency156untrack(() => {157lastUpdate = Date.now();158});159});160161// Conditional logging without dependency162let debugMode = $state(false);163let data = $state({ items: [] });164165$effect(() => {166// React to data changes167processData(data);168169// Log only if debug mode, but don't react to debugMode changes170untrack(() => {171if (debugMode) {172console.log("Data processed:", data);173}174});175});176177// One-time initialization178let config = $state(null);179let initialLoad = $state(false);180181$effect(() => {182if (config && !initialLoad) {183// Load data based on config184loadInitialData(config);185186// Set flag without creating new reactive dependency187untrack(() => {188initialLoad = true;189});190}191});192```193194### flushSync195196Synchronously flushes any pending reactive updates. Forces immediate DOM updates.197198```typescript { .api }199/**200* Synchronously flush any pending state changes and update the DOM201* @param fn - Optional function to run before flushing202* @returns Return value of fn, or void if no fn provided203*/204function flushSync<T = void>(fn?: (() => T) | undefined): T;205```206207**Usage Examples:**208209```typescript210import { flushSync } from "svelte";211212let items = $state([]);213let container;214215function addItemAndScroll(newItem) {216// Add item217items = [...items, newItem];218219// Force immediate DOM update220flushSync();221222// Scroll to new item (DOM is already updated)223const newElement = container.lastElementChild;224newElement.scrollIntoView();225}226227// Batch updates with immediate flush228function batchUpdateWithFlush() {229flushSync(() => {230// Multiple state updates231count = 10;232name = "Updated";233active = true;234});235236// DOM is immediately updated here237measureAndAdjust();238}239240// Animation timing241let animationTarget = $state(0);242let element;243244function animateWithPreciseTiming() {245animationTarget = 100;246247// Ensure DOM updates immediately248flushSync();249250// Start animation with current DOM state251element.animate([252{ transform: "translateX(0px)" },253{ transform: `translateX(${animationTarget}px)` }254], { duration: 300 });255}256```257258### getAbortSignal259260Returns an AbortSignal that is aborted when the current effect or derived is re-run or destroyed.261262```typescript { .api }263/**264* Get an AbortSignal for the current effect or derived computation265* @returns AbortSignal that aborts when effect re-runs or is destroyed266*/267function getAbortSignal(): AbortSignal;268```269270**Usage Examples:**271272```typescript273import { getAbortSignal } from "svelte";274275let userId = $state(null);276let userProfile = $state(null);277278// Effect with automatic cancellation279$effect(() => {280if (!userId) return;281282const signal = getAbortSignal();283284// Fetch with automatic cancellation285fetch(`/api/users/${userId}`, { signal })286.then(r => r.json())287.then(profile => {288if (!signal.aborted) {289userProfile = profile;290}291})292.catch(err => {293if (!signal.aborted) {294console.error("Failed to fetch user:", err);295}296});297});298299// Derived value with async computation300let searchQuery = $state("");301let searchResults = $derived.by(() => {302if (!searchQuery) return [];303304const signal = getAbortSignal();305let results = [];306307// Async search with cancellation308searchAPI(searchQuery, { signal })309.then(data => {310if (!signal.aborted) {311results = data;312}313});314315return results;316});317318// WebSocket connection management319let connected = $state(false);320let websocket = $state(null);321322$effect(() => {323const signal = getAbortSignal();324325const ws = new WebSocket("ws://localhost:8080");326websocket = ws;327328ws.onopen = () => {329if (!signal.aborted) {330connected = true;331}332};333334ws.onclose = () => {335if (!signal.aborted) {336connected = false;337}338};339340// Cleanup when aborted341signal.addEventListener("abort", () => {342ws.close();343websocket = null;344connected = false;345});346});347```348349### Reactive Built-in Objects350351Svelte provides reactive versions of built-in JavaScript objects that automatically trigger updates when their contents change.352353#### SvelteDate354355A reactive version of the built-in Date object.356357```typescript { .api }358/**359* Reactive Date object that triggers updates when date value changes360*/361class SvelteDate extends Date {362constructor(...params: any[]);363}364```365366**Usage Examples:**367368```typescript369import { SvelteDate } from "svelte/reactivity";370371const date = new SvelteDate();372373// Reactive clock374$effect(() => {375const interval = setInterval(() => {376date.setTime(Date.now());377}, 1000);378379return () => clearInterval(interval);380});381382// Use in template - updates automatically383// <p>Current time: {date.toLocaleTimeString()}</p>384```385386#### SvelteSet387388A reactive version of the built-in Set object.389390```typescript { .api }391/**392* Reactive Set that triggers updates when contents change393*/394class SvelteSet<T> extends Set<T> {395constructor(value?: Iterable<T> | null | undefined);396add(value: T): this;397}398```399400**Usage Examples:**401402```typescript403import { SvelteSet } from "svelte/reactivity";404405const tags = new SvelteSet(["svelte", "reactive"]);406407// Reactive size408const tagCount = $derived(tags.size);409410// Reactive membership check411const hasUrgent = $derived(tags.has("urgent"));412413function toggleTag(tag) {414if (tags.has(tag)) {415tags.delete(tag);416} else {417tags.add(tag);418}419}420```421422#### SvelteMap423424A reactive version of the built-in Map object.425426```typescript { .api }427/**428* Reactive Map that triggers updates when contents change429*/430class SvelteMap<K, V> extends Map<K, V> {431constructor(value?: Iterable<readonly [K, V]> | null | undefined);432set(key: K, value: V): this;433}434```435436**Usage Examples:**437438```typescript439import { SvelteMap } from "svelte/reactivity";440441const gameBoard = new SvelteMap();442let currentPlayer = $state("X");443444// Reactive game state445const winner = $derived(checkWinner(gameBoard));446const isFull = $derived(gameBoard.size === 9);447448function makeMove(position) {449if (!gameBoard.has(position) && !winner) {450gameBoard.set(position, currentPlayer);451currentPlayer = currentPlayer === "X" ? "O" : "X";452}453}454```455456#### SvelteURL457458A reactive version of the built-in URL object.459460```typescript { .api }461/**462* Reactive URL that triggers updates when URL properties change463*/464class SvelteURL extends URL {465get searchParams(): SvelteURLSearchParams;466}467```468469**Usage Examples:**470471```typescript472import { SvelteURL } from "svelte/reactivity";473474const url = new SvelteURL("https://example.com/path");475476// Reactive URL properties477const fullUrl = $derived(url.href);478const currentPath = $derived(url.pathname);479480// Update URL reactively481function updatePath(newPath) {482url.pathname = newPath;483}484485function updateQuery(key, value) {486url.searchParams.set(key, value);487}488```489490#### SvelteURLSearchParams491492A reactive version of URLSearchParams.493494```typescript { .api }495/**496* Reactive URLSearchParams that triggers updates when parameters change497*/498class SvelteURLSearchParams extends URLSearchParams {499constructor(init?: string | URLSearchParams | Record<string, string>);500}501```502503**Usage Examples:**504505```typescript506import { SvelteURLSearchParams } from "svelte/reactivity";507508const params = new SvelteURLSearchParams("?page=1&sort=name");509510// Reactive parameter access511const currentPage = $derived(params.get("page") || "1");512const sortField = $derived(params.get("sort") || "id");513514// Reactive parameter iteration515const allParams = $derived(Array.from(params.entries()));516517function updateSort(field) {518params.set("sort", field);519}520```521522#### MediaQuery523524Creates a reactive media query that updates based on viewport changes.525526```typescript { .api }527/**528* Reactive media query that updates when conditions change529*/530class MediaQuery {531constructor(query: string, fallback?: boolean);532get current(): boolean;533}534```535536**Usage Examples:**537538```typescript539import { MediaQuery } from "svelte/reactivity";540541const isLargeScreen = new MediaQuery("(min-width: 1024px)");542const prefersReducedMotion = new MediaQuery("(prefers-reduced-motion: reduce)");543const isDarkMode = new MediaQuery("(prefers-color-scheme: dark)");544545// Use in reactive context546const layoutClass = $derived(547isLargeScreen.current ? "desktop-layout" : "mobile-layout"548);549550const animationDuration = $derived(551prefersReducedMotion.current ? 0 : 300552);553```554555#### createSubscriber556557Creates a subscribe function for integrating external event-based systems.558559```typescript { .api }560/**561* Create a subscriber for external event-based systems562* @param start - Function called when first subscription occurs563* @returns Subscribe function564*/565function createSubscriber(566start: (update: () => void) => (() => void) | void567): () => void;568```569570**Usage Examples:**571572```typescript573import { createSubscriber } from "svelte/reactivity";574575// Custom reactive WebSocket576class ReactiveWebSocket {577#ws;578#subscribe;579#data = null;580581constructor(url) {582this.#subscribe = createSubscriber((update) => {583this.#ws = new WebSocket(url);584585this.#ws.onmessage = (event) => {586this.#data = JSON.parse(event.data);587update(); // Trigger reactive updates588};589590return () => {591this.#ws.close();592};593});594}595596get data() {597this.#subscribe(); // Make this getter reactive598return this.#data;599}600}601602// Usage603const ws = new ReactiveWebSocket("ws://localhost:8080");604605$effect(() => {606console.log("WebSocket data:", ws.data);607});608```609610## Advanced Patterns611612### Debounced Effects613614```typescript615let searchTerm = $state("");616let debouncedSearch = $state("");617618$effect(() => {619const signal = getAbortSignal();620const timeout = setTimeout(() => {621if (!signal.aborted) {622debouncedSearch = searchTerm;623}624}, 300);625626signal.addEventListener("abort", () => {627clearTimeout(timeout);628});629});630```631632### Batch Updates633634```typescript635function batchUpdates(updates) {636return new Promise(resolve => {637updates();638tick().then(resolve);639});640}641642// Usage643await batchUpdates(() => {644count = 10;645name = "New name";646items = [...items, newItem];647});648```649650### Reactive Cleanup651652```typescript653let resource = $state(null);654655$effect(() => {656const signal = getAbortSignal();657658// Create resource659resource = createExpensiveResource();660661// Cleanup when effect re-runs or component unmounts662signal.addEventListener("abort", () => {663resource?.cleanup();664resource = null;665});666});667```668669## Types670671```typescript { .api }672interface AbortSignal {673readonly aborted: boolean;674readonly reason: any;675addEventListener(type: "abort", listener: () => void): void;676removeEventListener(type: "abort", listener: () => void): void;677}678```679680## Best Practices6816821. **Use tick() for DOM reads**: Always await `tick()` before reading DOM measurements6832. **Use settled() for complex chains**: When multiple reactive values might update6843. **Use untrack() sparingly**: Only when you truly don't want reactive dependencies6854. **Avoid flushSync() in effects**: Can cause infinite loops or performance issues6865. **Always handle AbortSignal**: Check `signal.aborted` before state updates in async operations6876. **Combine with proper cleanup**: Use abort signals with proper resource cleanup patterns