SuperAPI AI Directory

svelte-special-elements

Frontend & websites

View repository

Updated 10-15 21:48

About this skill

Svelte Special Elements Reference (Svelte 5)

This skill covers special elements in Svelte templates (prefixed with svelte: ), used for scenarios such as error boundaries, async loading states, window/document/event listeners, dynamic tags, head injection, compiler options, etc.

When to use this skill

Use when the user needs to catch rendering errors or async pending states (<svelte:boundary>), listen to window / document / body events, dynamically render HTML tags (<svelte:element>), inject content into document.head(<svelte:head>), or configure compiler options/custom elements (<svelte:options>).


Critical: <svelte:boundary> (Svelte 5.3+)

Error and async boundaries, "isolating" parts of the app to handle errors and pending states. Boundaries catch synchronous errors thrown during rendering,$effect errors in await expression rejections; errors not in the rendering flow such as event handlers,setTimeoutevent-triggered async work, etc.will not becaught.

Three key properties

Property Type Description
pending Snippet Shown on initial render until all await resolve (onlyshown on initial render)
failed Snippet<[error, reset]> Shown when an error occurs, receives error and a recoverable reset function
onerror (error, reset) => void Called when an error occurs, commonly used for reporting to Sentry etc.; triggers in parallel with failed .
<svelte:boundary onerror={(e) => report(e)}>
  <FlakyComponent />

  {#snippet pending()}
    <p>加载中…</p>
  {/snippet}

  {#snippet failed(error, reset)}
    <button onclick={reset}>oops! try again</button>
  {/snippet}
</svelte:boundary>

SSR: transformError (Svelte 5.51+)

By default, error boundaries are on the serverinvalid—once rendering errors, the entire render(...) call fails. Since 5.51, you can pass a render(...) / mount(...) / hydrate(...) to transformError function, which must return a JSON-stringifiable object, used to render within the failed fragment (serialized to HTML during SSR, used for hydration after deserialization on the client).

import { render } from 'svelte/server';
const { head, body } = await render(App, {
  transformError: (error) => {
    console.error(error); // 保留原始错误用于日志
    return { message: 'An error occurred!' }; // 返回脱敏后的安全对象
  }
});

In onerror rethrow

If an error is thrown in onerror (or the original error is rethrown), the error will beouterboundary caught—can be used to report the error to a global boundary while preserving the current failed UI.

reset mode

reset is an ordinary function—can be stored in state and called from anywhere (including global UI outside the boundary, keyboard shortcuts, etc.):

<script>
  let error = $state(null);
  let reset = $state(() => {});
  function onerror(e, r) { error = e; reset = r; }
</script>

<svelte:boundary {onerror}>
  <FlakyComponent />
</svelte:boundary>

{#if error}
  <button onclick={() => { error = null; reset(); }}>oops! try again</button>
{/if}

Full examples and reference:examples/boundary-examples.md、references/boundary-reference.md


Critical: <svelte:window>

Listen to window events and bind window properties:

<svelte:window onkeydown={handleKey} onresize={handleResize} />
<svelte:window bind:scrollX bind:scrollY bind:innerWidth bind:innerHeight />

Bindable properties:

Property Type Read-only Description
innerWidth / innerHeight number Yes Viewport width/height (CSS pixels)
outerWidth / outerHeight number Yes Browser window outer dimensions (including chrome)
scrollX / scrollY number No Scroll position (the only writablewindow binding)
online boolean Yes navigator.onLine alias
devicePixelRatio number Yes device pixel ratio of the current display

Listenable events: all window-level events—keyboard (onkeydown / onkeyup), mouse (onclick / onmousemove etc.), touch (ontouchstart / ontouchmove)、pointer (onpointerdown etc.), wheel (onwheel)、clipboard (oncopy / oncut / onpaste)、drag (ondrag series)、focus (onfocus / onblur)、resource (onload / onerror / onscroll / onresize) etc.

<svelte:window> can only appear at the top level of a component, not inside block-level elements or conditional blocks.

On initial mountdoes notscroll the page to scrollX / scrollY 's initial value (for accessibility reasons); only subsequent value changes trigger scrolling. If you need to scroll on mount, call $effect in scrollTo()。


Critical: <svelte:document>

listen for document-level events (window events not supported):

<svelte:document onvisibilitychange={handleVisibility} />
<svelte:document {@attach myAttachment} />

Bindable properties(All readonly):

Property Type Description
activeElement Element | null Currently focused element
fullscreenElement Element | null Currently fullscreen element
pointerLockElement Element | null Pointer-locked element
visibilityState 'visible' | 'hidden' Document visibility

Most commonly used events:onvisibilitychange(tab switching)、onselectionchange(text selection change)、onreadystatechange、onfullscreenchange、onpointerlockchange、oncopy / oncut / onpaste etc.

<svelte:document> can also only appear at the top level; supports {@attach ...} to attach custom behavior to document .


Critical: <svelte:body>

Listen for events on the body element (such as mouseenter、mouseleave, which do not fire on window):

<svelte:body onmouseenter={handleMouseenter} onmouseleave={handleMouseleave} use:someAction />

<svelte:body> also supports use: action (this is the only clean way to add an action to <body> ). It can also only appear at the top level.


Critical: <svelte:head>

Insert content into document.head ; during SSRexposed separatelyoutside the body, the framework will put the head content into the HTML <head> tag.

<svelte:head>
  <title>Hello world!</title>
  <meta name="description" content="SEO description" />
  <meta property="og:title" content="OG title" />
  <link rel="canonical" href="/current-url" />
</svelte:head>

Supported elements:

Element Purpose
<title> Document title
<meta> SEO(name="description")、Open Graph(property="og:...")、Twitter Card、robots directives
<link rel="stylesheet" /> Per-page/per-theme stylesheets
<link rel="canonical" /> Canonical URL
<link rel="prefetch" | rel="preload" /> Resource prefetch/preload
<style> Inline critical CSS
<script type="application/ld+json"> JSON-LD structured data

Key behaviors:

  • Reactive:$state / $derived When it changes, the head updates automatically.
  • Duplicate merging: for elements of the same kind (such as two <title>) the later rendered one overrides the previous one (not appended repeatedly).
  • Multiple blocks: a single component can have multiple <svelte:head>, all merged into the head.
  • SSR exposed separately:render() returns { head, body }, the framework needs to put head into the <head> tag.

Complete example:examples/svelte-head-examples.md、references/svelte-head-reference.md


Critical: <svelte:element>

Dynamically render unknown tags (such as from a CMS or database):

<script>
  let tag = $state('hr');
</script>

<svelte:element this={tag}>内容</svelte:element>
<svelte:element this={tag} xmlns="http://www.w3.org/2000/svg" />

Behavior rules:

  • this is null / undefined → element is not rendered
  • this is a void element (br、hr、img etc.) but has child elements → runtime error in development mode
  • Svelte automatically infers the namespace (svg, mathml); you can use xmlns to specify it explicitly
  • this must be a valid DOM tag name (such as div / circle);#text、svelte:head etc. are invalid

The only supported binding:bind:this(because generic elements do not support Svelte built-in bindings such as bind:value)


Critical: <svelte:options>

Set compiler options:

<svelte:options runes={true} />
<svelte:options namespace="svg" />
<svelte:options customElement="my-element" />
<svelte:options css="injected" />
Options Type Description
runes={true|false} boolean Force entering/exiting Runes Mode
namespace="html|svg|mathml" string Component namespace (default html)
customElement={...} string | object Compile as a custom element (string means tag)
css="injected" string Inline style injection (SSR → style tag; CSR → JS)

<svelte:options> must be placed after <script> and before the template.

Legacy (deprecated) options(ineffective in Runes mode):immutable={true|false}、accessors={true|false}。


Quick Fixes

Problem Solution
Want to listen to visibilitychange / selectionchange Use <svelte:document> instead of <svelte:window>
Want to listen to mouseenter / mouseleave Use <svelte:body>
Dynamic tag does not render Check whether this is nullish
Styles do not take effect Use css="injected" to force inlining
A render error crashes the entire app Use <svelte:boundary> + failed fragment to isolate
Show a skeleton screen during async loading Use <svelte:boundary> + pending fragment (onlyfirst render)
Want to report to Sentry during rendering Use <svelte:boundary onerror={...}>
Want reset to trigger outside the boundary Store error / reset in $state
Dynamically change <title> or <meta> Use <svelte:head> to wrap reactive expressions

Gotchas

  1. Can only appear at the top level — svelte:window/document/body/head/element cannot be inside {#if} or other block-level elements.
  2. SSR behavior differs — <svelte:head> During SSR, the content is exposed separately and is not inside body;<svelte:boundary> is ineffective for SSR by default (available since 5.51+ with transformError enabled).
  3. svelte:element is a generic binding — does not support bind:value and other element-specific bindings.
  4. svelte:window 's scrollX / scrollY is the only writable binding — all others are readonly.
  5. <svelte:boundary> does not catch errors in event handlers / setTimeout error in — these are not part of the rendering flow.
  6. <svelte:boundary> 's pending is only shown on the initial render — for subsequent async updates use $effect.pending()。

FAQ

Q: <svelte:boundary> and try/catch? A: svelte:boundary catches synchronous/asynchronous errors during rendering and errors in $effect ; try/catch can only catch synchronous errors. boundary can also work with {#snippet pending} to handle the initial async loading state.

Q: When to use onerror, and when to use failed? A: failed is UI — determines what todisplay;onerror is a side effect — determines what todo(such as reporting to Sentry). The two are completely independent; you can use only one, or both at the same time.

Q: svelte:element and a regular component? A: svelte:element renders HTML tags (not Svelte components), suitable for scenarios where the tag is determined at runtime, such as CMS content.

Q: When to use namespace="svg"? A: When the component will be used as an SVG child element (such as <Icon.svelte> as <svg> inside <g> used).

Q: mount / hydrate / render How to pass transformError? A: They are all the same signature—pass a function that takes a (error) => JSON-stringifiable-object function:

import { mount, hydrate } from 'svelte';
import { render } from 'svelte/server';

mount(App, { target, transformError: (e) => ({ message: e.message }) });
hydrate(App, { target, transformError: (e) => ({ message: 'Hydration failed' }) });
const { head, body } = await render(App, { transformError: (e) => ({ message: '...' }) });

Q: Can the same <svelte:head> block be used in multiple components? A: No—<svelte:head> is component-level scoped. But you can split the head content into snippets, import them separately in multiple components, or wrap a <MetaTags> component.

Q: <svelte:window> Do event handlers affect performance? A: onresize / onscroll For high-frequency events like these, throttling/debouncing is recommended; the overhead of other events is negligible. Svelte automatically removes listeners when the component is destroyed, so no manual cleanup is needed.


Examples

Practical examples demonstrating all svelte: special elements.

File Description
examples/boundary-examples.md Comprehensive examples for <svelte:boundary>: pending, failed, onerror, transformError, error reporting, nested boundaries
examples/svelte-head-examples.md <svelte:head> examples: SEO meta, Open Graph, structured data, dynamic stylesheets, SSR head extraction
examples/svelte-element-examples.md Examples for <svelte:window>, <svelte:document>, <svelte:body>, <svelte:element>, <svelte:component>, <svelte:self>, <svelte:options>

Quick Examples

  • svelte:boundary: error fallback, loading skeleton, Sentry reporting, SSR transformError
  • svelte:window: keyboard shortcuts, resize handling, scroll position binding
  • svelte:document: page visibility, text selection tracking
  • svelte:body: mouse enter/leave events
  • svelte:head: dynamic <title>, Open Graph meta, JSON-LD, per-page stylesheets
  • svelte:element: dynamic heading levels (h1-h6), conditional tags, SVG namespace
  • svelte:component: dynamic component switching
  • svelte:options: customElement, runes mode, SVG namespace

References

Detailed reference documentation for all special elements and compiler options.

File Description
references/boundary-reference.md Full reference for <svelte:boundary> — pending/failed/onerror, transformError (5.51+), nesting, what is/isn't caught
references/svelte-head-reference.md Full reference for <svelte:head> — SSR behavior, supported elements, hydration, reactivity
references/svelte-window-document-body-reference.md All events and bindable properties for <svelte:window> / <svelte:document> / <svelte:body>
references/svelte-element-reference.md Reference for <svelte:element>, <svelte:component>, <svelte:self>, <svelte:fragment>
references/svelte-options-reference.md Full reference for <svelte:options> — customElement, runes, namespace, css, and all compiler options