SuperAPI AI Directory

svelte-reference

Frontend & websites

View repository

Updated 10-16 08:47

About this skill

Svelte API Reference (Svelte 5)

This skill is a quick reference for the official Svelte module APIs, including svelte/store、svelte/action、svelte/transition、svelte/animate、svelte/easing、svelte/events、svelte/compiler and common compiler/runtime error codes.

When to use this skill

Use this skill when the user needs to look up the API signatures of specific Svelte modules, use the transition / in / out / animate directive, theuse: action、easing function, the meaning of error codes, or needs compiler configuration.

Critical: svelte/store

import { writable, readable, derived, readonly, get } from 'svelte/store';
Function Signature Description
writable (initial, start?) => { subscribe, set, update } Writable store
readable (initial, start) => { subscribe } Read-only store (the value can only be set internally by start )
derived (stores, fn, initial?) => { subscribe } Derived store
readonly (store) => store Returns a read-only version (no set/update)
get (store) => value Get the value without subscribing (synchronous, creates a temporary subscription)

Store Contract

store = {
  subscribe: (subscription: (value: any) => void) => (() => void),
  set?: (value: any) => void
}

When to Use Stores vs Runes

  • Prefer runes ($state in .svelte.js files) for shared state and logic extraction.
  • Use stores when you have complex async data streams, need manual control over updates, or want RxJS-style operators.

writable Start Function

writable(initial, start) — the start callback is called when the subscriber count goes 0 → 1 (not 1 → 2). Return a stop function that runs when subscribers go 1 → 0. The start callback also receives an update function (in addition to set) for transform-based updates.

derived Forms

// single store
const doubled = derived(a, ($a) => $a * 2);

// array of stores
const sum = derived([a, b], ([$a, $b]) => $a + $b);

// async — second arg is `set`, third is `update`, third `derived` arg is initial value
const delayed = derived(a, ($a, set) => {
  setTimeout(() => set($a), 1000);
}, 0);

// with cleanup — return a function from the callback
const tick = derived(frequency, ($frequency, set) => {
  const id = setInterval(() => set(Date.now()), 1000 / $frequency);
  return () => clearInterval(id);
}, 0);

get(store) Caveat

Creates a temporary subscription, reads, then unsubscribes. Avoid in hot paths.

Critical: svelte/action (use: directive)

Actions are functions called when an element is mounted, added with the use: directive:

<script>
  /** @type {import('svelte/action').Action} */
  function myAction(node) {
    // node: HTMLElement — runs once on mount (client only, not SSR)
    $effect(() => {
      // setup
      return () => {
        // teardown — runs on unmount
      };
    });
  }
</script>

<div use:myAction>...</div>

[!NOTE] In Svelte 5.29 and newer, consider using {@attach ...} instead — more flexible and composable.

Action With Parameter

The parameter is not reactive — the action runs once on mount. Use $effect inside to react to parameter changes.

<script>
  /** @type {import('svelte/action').Action<HTMLInputElement, number>} */
  function debounce(node, delay) {
    $effect(() => {
      const handler = () => setTimeout(() => node.dispatchEvent(new Event('done')), delay);
      node.addEventListener('input', handler);
      return () => node.removeEventListener('input', handler);
    });
  }
</script>

<input use:debounce={300} />

Legacy update/destroy Form

<script>
  /** @type {import('svelte/action').Action<HTMLDivElement, string>} */
  function colorize(node, color) {
    node.style.color = color;
    return {
      update(newColor) { node.style.color = newColor; },
      destroy() { node.style.color = ''; }
    };
  }
</script>

<div use:colorize={'red'}>...</div>

Prefer the $effect form for new code.

Typing — Action<Node, Parameter, Events>

<script lang="ts">
  import type { Action } from 'svelte/action';

  const gestures: Action<HTMLDivElement, undefined, {
    onswipeleft: (e: CustomEvent) => void;
    onswiperight: (e: CustomEvent) => void;
  }> = (node) => {
    // dispatch: node.dispatchEvent(new CustomEvent('swipeleft'));
  };
</script>

<div use:gestures onswipeleft={next} onswiperight={prev}>...</div>

The third type parameter makes onswipeleft / onswiperight type-check in the template.

Critical: svelte/transition (transition: directive)

<script>
  import { fade, fly, slide, scale, blur, draw, crossfade } from 'svelte/transition';
</script>

{#if visible}
  <div transition:fade={{ duration: 300, delay: 100 }}>fade</div>
  <div transition:fly={{ y: 20, duration: 300 }}>fly</div>
  <div transition:slide>slide</div>
  <div transition:scale={{ start: 0.5, duration: 300 }}>scale</div>
  <div transition:blur={{ amount: 10 }}>blur</div>
{/if}

transition: is bidirectional — reverses on interrupt.

Built-in Transitions

Function Effect Key parameters
fade Opacity duration
fly Fly in from a position x, y, opacity
slide Slide axis: 'x' | 'y'
scale Scale start, opacity
blur Blur + opacity amount
draw SVG path drawing speed or duration
crossfade Paired crossfade duration, fallback

Transition Parameters

{
  delay?: number,        // ms before starting (default 0)
  duration?: number,     // ms (default 400)
  easing?: function,     // easing (default linear)
  css?: (t, u) => string,// web animation CSS (preferred)
  tick?: (t, u) => void  // imperative (use only when CSS cannot)
}

t runs 0 → 1 on intro, 1 → 0 on outro. u = 1 - t. Easing is applied to t before it reaches css / tick. css and tick are mutually exclusive.

Local vs Global

<!-- local: only animates when this block is created/destroyed -->
<div transition:fade>...</div>

<!-- global: animates whenever ANY ancestor block toggles -->
<div transition:fade|global>...</div>

Transition Events

Event Fires
introstart before intro animation
introend after intro animation
outrostart before outro animation
outroend after outro animation
<div
  transition:fly={{ y: 200, duration: 2000 }}
  onintrostart={() => (status = 'intro started')}
  onoutroend={() => (status = 'outro ended')}
>...</div>

Custom Transition Function

// @noErrors
transition = (
  node: HTMLElement,
  params: any,
  options: { direction: 'in' | 'out' | 'both' }
) => {
  delay?: number;
  duration?: number;
  easing?: (t: number) => number;
  css?: (t: number, u: number) => string;
  tick?: (t: number, u: number) => void;
}

If the function returns a function (instead of an object), Svelte calls it in the next microtask — this is what crossfade uses to coordinate paired transitions.

Critical: in: and out: (separate transitions)

in: and out: are unidirectional — they do not reverse on interrupt. If you toggle a block off mid-intro, the in-flight intro is abandoned and the out-transition restarts from t=0.

<script>
  import { fade, fly } from 'svelte/transition';
  let visible = $state(false);
</script>

{#if visible}
  <!-- flies in, fades out — NOT a reversible fly/fade -->
  <div in:fly={{ y: 200 }} out:fade>...</div>
{/if}
Directive When it runs Reversible on interrupt?
transition: enter or leave yes (reverses mid-flight)
in: enter only no (abandoned)
out: leave only no (always plays forward)

Use in: / out: when enter and exit animations should be visually different. The third argument to a custom transition function is { direction: 'in' | 'out' | 'both' }.

Critical: svelte/easing

import { cubicIn, cubicOut, cubicInOut, elasticOut, bounceOut } from 'svelte/easing';
Easing Description
linear Constant speed
quadIn/quadOut/quadInOut Quadratic
cubicIn/cubicOut/cubicInOut Cubic easing
quartIn/quartOut/quartInOut Quartic
quintIn/quintOut/quintInOut Quintic
sineIn/sineOut/sineInOut Sine
expoIn/expoOut/expoInOut Exponential
circIn/circOut/circInOut Circular
elasticIn/elasticOut/elasticInOut Elastic
backIn/backOut/backInOut Back
bounceIn/bounceOut/bounceInOut Bounce
<div transition:fly={{ y: 100, easing: cubicOut }}>...</div>

Critical: animate: (svelte/animate)

animate: runs when the index of an existing item changes inside a keyed {#each} block — not on add/remove. It must be on the immediate child of a keyed each block.

<script>
  import { flip } from 'svelte/animate';
  let items = $state(['apple', 'banana', 'cherry']);
</script>

{#each items as item (item)}
  <li animate:flip={{ duration: 400, easing: quintOut }}>{item}</li>
{/each}

flip (FLIP technique)

Measures from and to bounding rects, applies an inverse transform, then animates back to identity. See references/animations-reference.md for full API.

flip(node, {
  delay?: number,
  duration?: number | (node, { from, to }) => number,
  easing?: function
})

Custom Animation Function

// @noErrors
animation = (
  node: HTMLElement,
  { from: DOMRect, to: DOMRect },
  params: any
) => {
  delay?: number;
  duration?: number;
  easing?: (t: number) => number;
  css?: (t: number, u: number) => string;
  tick?: (t: number, u: number) => void;
}

from and to are the element's bounding rects before and after the reorder. Compute distance, angle, etc. to drive custom effects:

<script>
  import { cubicOut } from 'svelte/easing';

  function whizz(node, { from, to }) {
    const dx = from.left - to.left;
    const dy = from.top - to.top;
    const d = Math.sqrt(dx * dx + dy * dy);
    return {
      duration: Math.sqrt(d) * 120,
      easing: cubicOut,
      css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);`
    };
  }
</script>

{#each list as item (item)}
  <div animate:whizz>{item}</div>
{/each}

animate: does not run on add/remove — combine with in: / out: for those.

Critical: svelte/events

Provides the on function, replacing addEventListener(correctly handles event delegation and stopPropagation):

<script>
  import { on } from 'svelte/events';

  const handler = on(node, 'click', (event) => {
    // 正确处理委托和 stopPropagation
  }, { passive: true });
</script>

Critical: svelte/reactivity

$effect.tracking

$effect.tracking(); // boolean,是否在追踪上下文中

createSubscriber

Create a subscriber (only works in a tracking context):

import { createSubscriber } from 'svelte/reactivity';
const subscriber = createSubscriber((track) => {
  track(value); // 声明依赖
});

Critical: Compiler Errors (common)

Code Meaning Solution
2304 Undefined reference Check variable name spelling and imports
2322 Target element does not exist Check target selector
2554 Type mismatch Check TypeScript type annotations
2451 Modifying state outside an effect Do not assign directly in $effect in $state
7006 Incorrect argument type Check the function signature

Critical: Runtime Warnings (common)

Code Meaning Solution
ownership_invalid_mutation Modified non-own state Do not modify a prop directly; use $bindable
await_waterfall await dependency chain causes performance issues Refactor the data-fetching logic
state_teardown Attempted to update after destruction Ensure the component is not unmounted before accessing

Critical: svelte/compiler

Configuration options

import { compile } from 'svelte/compiler';
const result = compile(source, {
  filename: 'App.svelte',
  generate: 'dom',       // 'dom' | 'ssr' | false
  name: 'Component',      // 导出名
  format: 'esm',         // 'esm' | 'cjs'
  sveltePath: 'svelte',  // svelte 包路径
  dev: true,             // 开发模式(添加检查)
  css: 'injected',       // CSS 注入方式
  runes: false,           // 强制 Legacy Mode
  // ...
});

compile output

result.js.code;      // 编译后的 JS
result.css.code;     // 编译后的 CSS(如有)
result.warnings;     // 警告列表
result.stats;        // 编译统计

Quick Fixes

Problem Solution
Transition does not trigger Confirm the element is destroyed/recreated when the conditional block changes; use {#key}
in:/out: switching midway behaves strangely This is the expected behavior of unidirectional — only transition: is reversible
animate:flip does not work There must be (key) and animate: must be on a direct child element of the keyed eachdirect child elementon
flip Animation is not smooth Ensure the key is unique and stable
Easing function does not work Confirm that it is correctly imported from svelte/easing correctly imported
use: Parameter changes do not take effect action is called only once; use $effect to read parameters internally
Compiler error See the error code table above
Runtime warning Check the ownership chain

Examples

Practical usage patterns with detailed explanations:

References

Complete API documentation:

Gotchas

  1. svelte/transition of css and tick are mutually exclusive — only one of the two can be used
  2. in: / out: is irreversible — on interruption the in-flight intro is abandoned and the outro restarts from t=0
  3. animate: must be on a direct child element of the keyed each — animate: on a nested div will not run
  4. flip requires a stable key — use a unique ID instead of the array index
  5. animate: does not respond to add/remove — it only triggers on reorder
  6. Store subscribe returns an unsubscribe function — automatically unsubscribes when the component unmounts
  7. get(store) creates a temporary subscription — frequent calls affect performance
  8. elasticIn/elasticOut is slower — heavy use may affect performance
  9. use:action parameter changes do not trigger a re-call — use $effect to respond inside the action