Neben Form- und Media-Bindings bietet Svelte einige weitere Bindings, mit denen sich DOM-Referenzen, Element-Größen und Spezial-Elemente wie <details> oder contenteditable-Bereiche elegant ansprechen lassen. Dieser Artikel zeigt bind:this, alle Größen-Bindings (intern via ResizeObserver) und die Spezialfälle für details/contenteditable.
bind:this – Referenz auf das DOM-Element
bind:this speichert die Referenz auf den DOM-Knoten in einer Variable — analog zu Reacts useRef:
<script>
let input;
function focusInput() {
input?.focus();
}
</script>
<input bind:this={input} />
<button onclick={focusInput}>Fokussieren</button>Wichtig: Die Variable ist erst nach dem Mount gesetzt. Vor dem ersten Render ist sie undefined — Optional-Chaining (input?.focus()) verhindert Fehler.
Mit TypeScript
<script lang="ts">
let input: HTMLInputElement;
let canvas: HTMLCanvasElement;
let video: HTMLVideoElement;
</script>Größen-Bindings (Read-only)
Auf jedem HTML-Element verfügbar — die Werte werden über einen internen ResizeObserver versorgt und bleiben automatisch aktuell:
| Binding | Wert-Typ | Beschreibung |
|---|---|---|
bind:clientWidth | number | Sichtbare Breite ohne Scrollbar/Border |
bind:clientHeight | number | Sichtbare Höhe |
bind:offsetWidth | number | Außenbreite inkl. Border |
bind:offsetHeight | number | Außenhöhe |
bind:contentRect | DOMRectReadOnly | DOMRect aus dem ResizeObserver |
bind:contentBoxSize | Array | Content-Box-Maße |
bind:borderBoxSize | Array | Border-Box-Maße |
bind:devicePixelContentBoxSize | Array | Pixel-genaue Content-Box |
<script>
let width = $state(0);
let isCompact = $derived(width < 600);
</script>
<div bind:clientWidth={width} class:compact={isCompact}>
<p>Container: {width}px breit</p>
{#if isCompact}
<p>Kompakte Ansicht</p>
{:else}
<p>Standard-Ansicht</p>
{/if}
</div>contentRect für mehr Details
bind:contentRect liefert ein vollständiges DOMRectReadOnly-Objekt:
<script>
let rect = $state(null);
</script>
<div bind:contentRect={rect}>
Inhalt …
</div>
{#if rect}
<p>{rect.width.toFixed(0)} × {rect.height.toFixed(0)}</p>
{/if}bind:open für <details>
<details> hat einen aufklappbaren Zustand — bind:open macht ihn reaktiv:
<script>
let isOpen = $state(false);
</script>
<details bind:open={isOpen}>
<summary>FAQ-Eintrag</summary>
<p>Antwort …</p>
</details>
<p>Aktuell: {isOpen ? 'aufgeklappt' : 'eingeklappt'}</p>
<button onclick={() => isOpen = !isOpen}>Toggle</button>Contenteditable-Bindings
Wenn ein Element contenteditable ist, lassen sich seine Inhalte mit drei verschiedenen Bindings synchronisieren:
| Binding | Liefert/Empfängt |
|---|---|
bind:innerHTML | HTML-Markup |
bind:innerText | Sichtbarer Text (mit Whitespace) |
bind:textContent | Roher Text-Inhalt |
<script>
let html = $state('<strong>Klick</strong> mich an, um zu editieren.');
</script>
<div contenteditable="true" bind:innerHTML={html}></div>
<hr />
<pre>{html}</pre>Beim Tippen wird html aktualisiert. Setzt der Code html = '...', ändert sich auch der Editor-Inhalt.
Vorsicht: contenteditable-HTML kann beliebige Tags enthalten. Bei Speicherung sanitizen.
Praxis-Beispiel: Container mit responsivem Layout
<script>
let { children } = $props();
let width = $state(0);
let layout = $derived(
width < 480 ? 'narrow' :
width < 768 ? 'medium' : 'wide'
);
</script>
<article bind:clientWidth={width} class={`card layout-${layout}`}>
{@render children()}
</article>
<style>
.card { padding: 1rem; border: 1px solid #ddd; }
.layout-narrow { font-size: 0.9em; }
.layout-wide { padding: 2rem; }
</style>Die Komponente reagiert auf ihre eigene Container-Breite — ohne Window-Listener, ohne CSS-Container-Queries. Funktioniert in jedem Layout-Kontext.
Praxis-Beispiel: Canvas mit Auto-Resize
<script>
let canvas;
let width = $state(0);
let height = $state(0);
$effect(() => {
if (!canvas || width === 0) return;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, width, height);
});
</script>
<div bind:clientWidth={width} bind:clientHeight={height} style="height: 200px">
<canvas bind:this={canvas}></canvas>
</div>bind:clientWidth und bind:clientHeight reagieren auf Layout-Änderungen — der Canvas wird automatisch neu skaliert und gezeichnet.
Häufige Stolperfallen
bind:this zu früh nutzen.
Im <script>-Top-Level ist die Variable undefined — sie wird erst beim Mount belegt. Mit $effect(() => { if (input) input.focus(); }) arbeiten oder Optional-Chaining nutzen.
Größen-Bindings auf inline-Elementen.
Bei display: inline haben viele Browser keine sinnvolle Höhe — der Wert kann 0 bleiben. Lieber auf Block- oder Flex-Elemente binden.
bind:contentRect synchron im <script> lesen.
Direkt nach Mount ist der Wert noch null. Im $effect mit Null-Check arbeiten.
Zwei Bindings auf demselben Wert kollidieren.
Mehrere Größen-Bindings sind okay (jedes liefert seinen eigenen Wert). Ein bind:innerHTML und bind:textContent gleichzeitig führt zu Konflikten — nur eines verwenden.
bind:innerHTML ohne contenteditable.
Ohne das Attribut ist das Element nicht editierbar — Svelte schreibt zwar den Inhalt, aber der Nutzer kann nicht eingeben.