Werte und JavaScript-Ausdrücke werden in Svelte mit geschweiften Klammern im Markup eingebunden — eine Syntax, die JSX-erfahrenen Entwicklern sofort vertraut ist. Dieser Artikel zeigt die Grundlagen: Werte ausgeben, Attribute setzen, Boolean-Verhalten, automatisches Escaping gegen XSS und wie man in Texten ein literales { schreibt.
Werte ausgeben
Jeder Ausdruck zwischen { und } im Markup wird zur Render-Zeit ausgewertet:
<script>
let name = $state('Anna');
let age = $state(30);
</script>
<p>Hallo, {name}!</p>
<p>Alter: {age}</p>
<p>Geboren: {2026 - age}</p>
<p>Vollerwachsen: {age >= 18 ? 'Ja' : 'Nein'}</p>
<p>Großgeschrieben: {name.toUpperCase()}</p>In den Klammern sind nur Ausdrücke erlaubt — also alles, was einen Wert ergibt. Anweisungen wie if, for oder let funktionieren dort nicht. Für Bedingungen und Schleifen gibt es eigene Block-Syntax (siehe {#if} und {#each}).
Attribute mit dynamischen Werten
Attribute lassen sich genauso mit Klammern setzen:
<script>
let user = { name: 'Anna', avatarUrl: '/avatars/anna.jpg' };
let buttonClass = 'btn btn-primary';
</script>
<img src={user.avatarUrl} alt={user.name} />
<button class={buttonClass}>Klick</button>
<a href={`/users/${user.id}`}>Profil</a>Statische Werte stehen wie üblich in Anführungszeichen (alt="Avatar"), dynamische in geschweiften Klammern.
Attribute-Shorthand
Wenn der Wert exakt den Attribut-Namen hat, gibt es eine Kurzform:
<!-- Lange Form -->
<img src={src} alt={alt} />
<!-- Shorthand -->
<img {src} {alt} />Spread-Attribute
Bei Wrapper-Elementen lässt sich ein Objekt mit allen Attributen via Spread setzen:
<script>
const inputProps = {
type: 'email',
placeholder: 'name@example.com',
required: true,
};
</script>
<input {...inputProps} />Funktioniert sowohl bei HTML-Elementen als auch bei Komponenten.
Boolean-Attribute
Bei Boolean-HTML-Attributen reicht der Attribut-Name allein — gleichbedeutend mit attr={true}:
<input type="checkbox" checked /> <!-- true -->
<input type="checkbox" checked={false} /> <!-- false -->
<input type="checkbox" checked={isOn} /> <!-- dynamisch -->
<button disabled={loading}>Speichern</button>Bei false setzt Svelte das Attribut gar nicht ans DOM-Element — was dem HTML-Standard entspricht.
Automatisches HTML-Escaping
Werte, die mit {expression} ausgegeben werden, werden automatisch HTML-escaped — das schützt zuverlässig vor XSS-Angriffen:
<script>
let userInput = '<script>alert("xss")</script>';
</script>
<!-- Wird als Text gerendert, NICHT als Script ausgeführt -->
<p>{userInput}</p>Das gerenderte HTML enthält wörtlich <script>... — kein ausführbarer Code.
Wenn du bewusst HTML rendern willst, gibt es das {@html ...}-Tag (siehe Special Tags). Vorsicht: Damit fällt der XSS-Schutz weg — nur mit vertrauenswürdigen Quellen verwenden.
Geschweifte Klammern als Text
Wenn { oder } im sichtbaren Text vorkommen sollen (z. B. in Code-Beispielen oder Templates), gibt es zwei Wege:
<!-- HTML-Entities -->
<p>Ein Set: {1, 2, 3}</p>
<!-- String-Literal -->
<p>{'{ Beispiel }'}</p>In Code-Blöcken (Markdown via <pre> oder ähnlich) ist die Variante mit String-Literal robuster.
Reaktivität in Expressions
Werte aus $state, $derived und $props werden automatisch verfolgt — der Compiler weiß, welche Stellen im Markup von welchen Variablen abhängen, und aktualisiert nur die nötigen DOM-Knoten:
<script>
let count = $state(0);
let user = $state({ name: 'Anna' });
</script>
<p>Count: {count}</p>
<p>User: {user.name}</p>
<button onclick={() => count++}>+1</button>Beim Klick aktualisiert sich nur der Text in <p>Count: ...</p> — nicht der gesamte Block.
Mehrzeilige Ausdrücke
Komplexe Ausdrücke gehen, sind aber meistens lesbarer als $derived-Werte ausgelagert:
<p>
{users.filter((u) => u.active)
.map((u) => u.name)
.sort()
.join(', ')}
</p><script>
let users = $state([...]);
let activeNames = $derived(
users
.filter((u) => u.active)
.map((u) => u.name)
.sort()
.join(', ')
);
</script>
<p>{activeNames}</p>Vorteil: Der Wert ist memoiziert und das Markup bleibt aufgeräumt.
Häufige Stolperfallen
null und undefined.
Werden als leerer String gerendert — keine Fehler, aber manchmal überraschend.
0 und leere Strings in Bedingungen.
{users.length && <UserList users={users} />}In Svelte gilt das gleiche wie in JSX: Bei leerer Liste rendert die 0. Stattdessen {#if} nutzen oder explizit > 0-Vergleich.
Funktionsaufrufe ohne Klammern.
{getName} gibt die Funktion als Text aus (function getName() {…}). Mit Klammern: {getName()}.
Anführungszeichen-Mix bei Attributen. Auch das klassische HTML-Pattern mit String-Interpolation in Attributwerten funktioniert in Svelte:
<!-- Klammer im String-Attribut -->
<a href="/users/{id}">Profil</a>
<!-- Template-String in Klammern (oft lesbarer) -->
<a href={`/users/${id}`}>Profil</a>