CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-svelte

A cybernetically enhanced web application framework that compiles to highly optimized JavaScript with reactive state management and component-based architecture.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

reactivity.mddocs/

Reactivity Control

Svelte provides functions for controlling reactive updates, managing execution timing, handling asynchronous operations, and reactive versions of built-in JavaScript objects for comprehensive reactivity.

Capabilities

tick

Returns a Promise that resolves after any pending state changes have been applied to the DOM.

/**
 * Returns a promise that resolves once any pending state changes have been applied
 * @returns Promise that resolves after DOM updates
 */
function tick(): Promise<void>;

Usage Examples:

import { tick } from "svelte";

let count = $state(0);
let element;

async function updateAndRead() {
  count += 1;
  
  // Wait for DOM to update
  await tick();
  
  // Now we can safely read the updated DOM
  console.log("Updated element text:", element.textContent);
}

// Measuring DOM changes
async function measureHeight(newContent) {
  const oldHeight = element.offsetHeight;
  
  // Update content
  content = newContent;
  
  // Wait for DOM update
  await tick();
  
  const newHeight = element.offsetHeight;
  console.log(`Height changed from ${oldHeight} to ${newHeight}`);
}

// Focusing elements after conditional rendering
let showInput = $state(false);
let inputElement;

async function showAndFocus() {
  showInput = true;
  
  // Wait for input to be rendered
  await tick();
  
  // Now we can focus it
  inputElement?.focus();
}

settled

Returns a Promise that resolves when all async state updates have completed. More comprehensive than tick() for complex reactive chains.

/**
 * Returns a promise that resolves when all reactive updates have settled
 * @returns Promise that resolves after all async updates
 */
function settled(): Promise<void>;

Usage Examples:

import { settled } from "svelte";

let loading = $state(false);
let data = $state([]);
let processedData = $state([]);

// Derived values that might trigger additional updates
let filteredData = $derived(data.filter(item => item.active));
let sortedData = $derived(filteredData.sort((a, b) => a.name.localeCompare(b.name)));

async function loadAndProcess() {
  loading = true;
  
  // Fetch data
  const response = await fetch("/api/data");
  data = await response.json();
  
  // Wait for all reactive updates to settle
  await settled();
  
  // Now all derived values are up to date
  console.log("Final processed data:", sortedData);
  loading = false;
}

// Complex reactive chains
let userInput = $state("");
let searchResults = $state([]);
let selectedItems = $state([]);

$effect(async () => {
  if (userInput.length > 2) {
    searchResults = await searchAPI(userInput);
  }
});

async function processSelection() {
  // Update multiple reactive values
  selectedItems = [...selectedItems, ...searchResults.slice(0, 3)];
  userInput = "";
  
  // Wait for all reactive updates to complete
  await settled();
  
  // Safe to perform operations that depend on final state
  saveSelections(selectedItems);
}

untrack

Executes a function without creating reactive dependencies or triggering reactive updates.

/**
 * Run a function without creating dependencies on reactive state
 * @param fn - Function to run without tracking
 * @returns Return value of the function
 */
function untrack<T>(fn: () => T): T;

Usage Examples:

import { untrack } from "svelte";

let count = $state(0);
let lastUpdate = $state(Date.now());

// Effect that doesn't depend on lastUpdate changes
$effect(() => {
  console.log(`Count is ${count}`);
  
  // Update timestamp without creating dependency
  untrack(() => {
    lastUpdate = Date.now();
  });
});

// Conditional logging without dependency
let debugMode = $state(false);
let data = $state({ items: [] });

$effect(() => {
  // React to data changes
  processData(data);
  
  // Log only if debug mode, but don't react to debugMode changes
  untrack(() => {
    if (debugMode) {
      console.log("Data processed:", data);
    }
  });
});

// One-time initialization
let config = $state(null);
let initialLoad = $state(false);

$effect(() => {
  if (config && !initialLoad) {
    // Load data based on config
    loadInitialData(config);
    
    // Set flag without creating new reactive dependency
    untrack(() => {
      initialLoad = true;
    });
  }
});

flushSync

Synchronously flushes any pending reactive updates. Forces immediate DOM updates.

/**
 * Synchronously flush any pending state changes and update the DOM
 * @param fn - Optional function to run before flushing
 * @returns Return value of fn, or void if no fn provided
 */
function flushSync<T = void>(fn?: (() => T) | undefined): T;

Usage Examples:

import { flushSync } from "svelte";

let items = $state([]);
let container;

function addItemAndScroll(newItem) {
  // Add item
  items = [...items, newItem];
  
  // Force immediate DOM update
  flushSync();
  
  // Scroll to new item (DOM is already updated)
  const newElement = container.lastElementChild;
  newElement.scrollIntoView();
}

// Batch updates with immediate flush
function batchUpdateWithFlush() {
  flushSync(() => {
    // Multiple state updates
    count = 10;
    name = "Updated";
    active = true;
  });
  
  // DOM is immediately updated here
  measureAndAdjust();
}

// Animation timing
let animationTarget = $state(0);
let element;

function animateWithPreciseTiming() {
  animationTarget = 100;
  
  // Ensure DOM updates immediately
  flushSync();
  
  // Start animation with current DOM state
  element.animate([
    { transform: "translateX(0px)" },
    { transform: `translateX(${animationTarget}px)` }
  ], { duration: 300 });
}

getAbortSignal

Returns an AbortSignal that is aborted when the current effect or derived is re-run or destroyed.

/**
 * Get an AbortSignal for the current effect or derived computation
 * @returns AbortSignal that aborts when effect re-runs or is destroyed
 */
function getAbortSignal(): AbortSignal;

Usage Examples:

import { getAbortSignal } from "svelte";

let userId = $state(null);
let userProfile = $state(null);

// Effect with automatic cancellation
$effect(() => {
  if (!userId) return;
  
  const signal = getAbortSignal();
  
  // Fetch with automatic cancellation
  fetch(`/api/users/${userId}`, { signal })
    .then(r => r.json())
    .then(profile => {
      if (!signal.aborted) {
        userProfile = profile;
      }
    })
    .catch(err => {
      if (!signal.aborted) {
        console.error("Failed to fetch user:", err);
      }
    });
});

// Derived value with async computation
let searchQuery = $state("");
let searchResults = $derived.by(() => {
  if (!searchQuery) return [];
  
  const signal = getAbortSignal();
  let results = [];
  
  // Async search with cancellation
  searchAPI(searchQuery, { signal })
    .then(data => {
      if (!signal.aborted) {
        results = data;
      }
    });
  
  return results;
});

// WebSocket connection management
let connected = $state(false);
let websocket = $state(null);

$effect(() => {
  const signal = getAbortSignal();
  
  const ws = new WebSocket("ws://localhost:8080");
  websocket = ws;
  
  ws.onopen = () => {
    if (!signal.aborted) {
      connected = true;
    }
  };
  
  ws.onclose = () => {
    if (!signal.aborted) {
      connected = false;
    }
  };
  
  // Cleanup when aborted
  signal.addEventListener("abort", () => {
    ws.close();
    websocket = null;
    connected = false;
  });
});

Reactive Built-in Objects

Svelte provides reactive versions of built-in JavaScript objects that automatically trigger updates when their contents change.

SvelteDate

A reactive version of the built-in Date object.

/**
 * Reactive Date object that triggers updates when date value changes
 */
class SvelteDate extends Date {
  constructor(...params: any[]);
}

Usage Examples:

import { SvelteDate } from "svelte/reactivity";

const date = new SvelteDate();

// Reactive clock
$effect(() => {
  const interval = setInterval(() => {
    date.setTime(Date.now());
  }, 1000);
  
  return () => clearInterval(interval);
});

// Use in template - updates automatically
// <p>Current time: {date.toLocaleTimeString()}</p>

SvelteSet

A reactive version of the built-in Set object.

/**
 * Reactive Set that triggers updates when contents change
 */
class SvelteSet<T> extends Set<T> {
  constructor(value?: Iterable<T> | null | undefined);
  add(value: T): this;
}

Usage Examples:

import { SvelteSet } from "svelte/reactivity";

const tags = new SvelteSet(["svelte", "reactive"]);

// Reactive size
const tagCount = $derived(tags.size);

// Reactive membership check
const hasUrgent = $derived(tags.has("urgent"));

function toggleTag(tag) {
  if (tags.has(tag)) {
    tags.delete(tag);
  } else {
    tags.add(tag);
  }
}

SvelteMap

A reactive version of the built-in Map object.

/**
 * Reactive Map that triggers updates when contents change
 */
class SvelteMap<K, V> extends Map<K, V> {
  constructor(value?: Iterable<readonly [K, V]> | null | undefined);
  set(key: K, value: V): this;
}

Usage Examples:

import { SvelteMap } from "svelte/reactivity";

const gameBoard = new SvelteMap();
let currentPlayer = $state("X");

// Reactive game state
const winner = $derived(checkWinner(gameBoard));
const isFull = $derived(gameBoard.size === 9);

function makeMove(position) {
  if (!gameBoard.has(position) && !winner) {
    gameBoard.set(position, currentPlayer);
    currentPlayer = currentPlayer === "X" ? "O" : "X";
  }
}

SvelteURL

A reactive version of the built-in URL object.

/**
 * Reactive URL that triggers updates when URL properties change
 */
class SvelteURL extends URL {
  get searchParams(): SvelteURLSearchParams;
}

Usage Examples:

import { SvelteURL } from "svelte/reactivity";

const url = new SvelteURL("https://example.com/path");

// Reactive URL properties
const fullUrl = $derived(url.href);
const currentPath = $derived(url.pathname);

// Update URL reactively
function updatePath(newPath) {
  url.pathname = newPath;
}

function updateQuery(key, value) {
  url.searchParams.set(key, value);
}

SvelteURLSearchParams

A reactive version of URLSearchParams.

/**
 * Reactive URLSearchParams that triggers updates when parameters change
 */
class SvelteURLSearchParams extends URLSearchParams {
  constructor(init?: string | URLSearchParams | Record<string, string>);
}

Usage Examples:

import { SvelteURLSearchParams } from "svelte/reactivity";

const params = new SvelteURLSearchParams("?page=1&sort=name");

// Reactive parameter access
const currentPage = $derived(params.get("page") || "1");
const sortField = $derived(params.get("sort") || "id");

// Reactive parameter iteration
const allParams = $derived(Array.from(params.entries()));

function updateSort(field) {
  params.set("sort", field);
}

MediaQuery

Creates a reactive media query that updates based on viewport changes.

/**
 * Reactive media query that updates when conditions change
 */
class MediaQuery {
  constructor(query: string, fallback?: boolean);
  get current(): boolean;
}

Usage Examples:

import { MediaQuery } from "svelte/reactivity";

const isLargeScreen = new MediaQuery("(min-width: 1024px)");
const prefersReducedMotion = new MediaQuery("(prefers-reduced-motion: reduce)");
const isDarkMode = new MediaQuery("(prefers-color-scheme: dark)");

// Use in reactive context
const layoutClass = $derived(
  isLargeScreen.current ? "desktop-layout" : "mobile-layout"
);

const animationDuration = $derived(
  prefersReducedMotion.current ? 0 : 300
);

createSubscriber

Creates a subscribe function for integrating external event-based systems.

/**
 * Create a subscriber for external event-based systems
 * @param start - Function called when first subscription occurs
 * @returns Subscribe function
 */
function createSubscriber(
  start: (update: () => void) => (() => void) | void
): () => void;

Usage Examples:

import { createSubscriber } from "svelte/reactivity";

// Custom reactive WebSocket
class ReactiveWebSocket {
  #ws;
  #subscribe;
  #data = null;
  
  constructor(url) {
    this.#subscribe = createSubscriber((update) => {
      this.#ws = new WebSocket(url);
      
      this.#ws.onmessage = (event) => {
        this.#data = JSON.parse(event.data);
        update(); // Trigger reactive updates
      };
      
      return () => {
        this.#ws.close();
      };
    });
  }
  
  get data() {
    this.#subscribe(); // Make this getter reactive
    return this.#data;
  }
}

// Usage
const ws = new ReactiveWebSocket("ws://localhost:8080");

$effect(() => {
  console.log("WebSocket data:", ws.data);
});

Advanced Patterns

Debounced Effects

let searchTerm = $state("");
let debouncedSearch = $state("");

$effect(() => {
  const signal = getAbortSignal();
  const timeout = setTimeout(() => {
    if (!signal.aborted) {
      debouncedSearch = searchTerm;
    }
  }, 300);
  
  signal.addEventListener("abort", () => {
    clearTimeout(timeout);
  });
});

Batch Updates

function batchUpdates(updates) {
  return new Promise(resolve => {
    updates();
    tick().then(resolve);
  });
}

// Usage
await batchUpdates(() => {
  count = 10;
  name = "New name";
  items = [...items, newItem];
});

Reactive Cleanup

let resource = $state(null);

$effect(() => {
  const signal = getAbortSignal();
  
  // Create resource
  resource = createExpensiveResource();
  
  // Cleanup when effect re-runs or component unmounts
  signal.addEventListener("abort", () => {
    resource?.cleanup();
    resource = null;
  });
});

Types

interface AbortSignal {
  readonly aborted: boolean;
  readonly reason: any;
  addEventListener(type: "abort", listener: () => void): void;
  removeEventListener(type: "abort", listener: () => void): void;
}

Best Practices

  1. Use tick() for DOM reads: Always await tick() before reading DOM measurements
  2. Use settled() for complex chains: When multiple reactive values might update
  3. Use untrack() sparingly: Only when you truly don't want reactive dependencies
  4. Avoid flushSync() in effects: Can cause infinite loops or performance issues
  5. Always handle AbortSignal: Check signal.aborted before state updates in async operations
  6. Combine with proper cleanup: Use abort signals with proper resource cleanup patterns

docs

compiler.md

context.md

easing.md

index.md

legacy.md

lifecycle.md

motion.md

reactivity-window.md

reactivity.md

rendering.md

runes.md

ssr.md

stores.md

transitions.md

tile.json