Du hast ein SvelteKit-Projekt aufgesetzt — Zeit für die erste eigene Komponente. Dieser Artikel führt durch den vollständigen Lebensweg einer Komponente: vom leeren .svelte-File bis zur Verwendung in der Anwendung. Du lernst, wie eine Komponente aufgebaut ist, wie Reaktivität mit $state funktioniert, wie Props übergeben werden und wie das Ganze sich in das SvelteKit-Routing einfügt.
Was ist eine Komponente in Svelte?
Eine Svelte-Komponente ist eine .svelte-Datei mit bis zu drei Bereichen: <script> für Logik, das Markup als Standard-Inhalt, und optional ein <style>-Block. Komponenten werden importiert und wie ein HTML-Tag verwendet — der Tag-Name ist großgeschrieben (<Greeting />).
Drei Regeln gelten in Svelte 5:
- Reaktive Variablen werden mit
$state(...)markiert. - Props werden mit
$props()ausgelesen. - Komponenten-Datei und -Tag-Name beginnen mit einem Großbuchstaben.
Schritt 1 – Datei anlegen
Im SvelteKit-Skeleton wandern wiederverwendbare Komponenten in src/lib/components/. Der Alias $lib zeigt auf src/lib/ und macht Imports kurz.
src/
lib/
components/
Greeting.svelte
routes/
+page.svelteSchritt 2 – Komponente schreiben
<script>
let { name = 'Welt' } = $props();
</script>
<h1>Hallo, {name}!</h1>
<style>
h1 {
color: teal;
font-family: system-ui, sans-serif;
}
</style>Was hier passiert:
$props()holt die Props der Komponente. Mit Destrukturierung lässt sich ein Default setzen — ohne übergebenen Wert wird'Welt'verwendet.{name}im Markup ist der Svelte-Ausdruck zum Einbinden von JavaScript-Werten (vergleichbar mit JSX{...}).<style>ist automatisch scoped: Dash1greift nur innerhalb dieser Komponente.
Schritt 3 – Komponente verwenden
In der Startseite +page.svelte importieren und einbinden:
<script>
import Greeting from '$lib/components/Greeting.svelte';
</script>
<main>
<Greeting name="Anna" />
<Greeting name="Bernd" />
<Greeting />
</main>Die ersten beiden Verwendungen übergeben einen Namen, die dritte nutzt den Default. Der Browser zeigt drei <h1>-Elemente in Teal.
Schritt 4 – Reaktive Werte mit $state
Statische Komponenten sind langweilig. Erweitern wir das Beispiel um einen Counter:
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
Geklickt: {count}
</button>
<style>
button {
padding: 0.5em 1em;
cursor: pointer;
}
</style>Drei Punkte zu beachten:
$state(0)machtcountreaktiv. Einelet-Variable allein wäre in Svelte 5 nicht reaktiv.count++löst automatisch ein Re-Render aus — keine Setter-Funktion nötig.onclick={...}ist Svelte-5-Syntax (nicht mehron:click).
Schritt 5 – Werte aus Eltern empfangen und ändern
Wenn die Eltern-Komponente den State lesen und beeinflussen will, gibt es zwei übliche Wege.
Variante A: Initial-Wert übergeben, lokal halten
<script>
import { untrack } from 'svelte';
let { initial = 0 } = $props();
let count = $state(untrack(() => initial));
</script>
<button onclick={() => count++}>
{count}
</button>initial ist eine Prop, count lebt lokal — Änderungen propagieren nicht zurück. Das untrack(() => initial) ist Pflicht-Lektüre für dieses Pattern: Es macht für den Compiler explizit, dass wir den Prop-Wert nur einmalig als Seed übernehmen wollen. Ohne diesen Wrap warnt Svelte mit „state_referenced_locally”, weil unklar ist, ob die fehlende Synchronisation gewollt ist.
Variante B: Callback-Prop für Updates
<script>
let { value, onChange } = $props();
</script>
<button onclick={() => onChange?.(value + 1)}>
{value}
</button><script>
import Counter from '$lib/components/Counter.svelte';
let count = $state(0);
</script>
<Counter value={count} onChange={(next) => (count = next)} />Diese Schreibweise entspricht React-style „lifted state”. Für Two-Way-Binding gibt es zusätzlich $bindable (Artikel: Bindings).
Schritt 6 – Komponente mit Children
Eine Komponente kann Inhalt zwischen ihren Tags entgegennehmen. In Svelte 5 läuft das über den Snippet-Prop children:
<script>
let { children } = $props();
</script>
<div class="card">
{@render children()}
</div>
<style>
.card {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 8px;
}
</style><Card>
<h2>Profil</h2>
<p>Anna, 30 Jahre</p>
</Card>Mehr zu Snippets im Artikel Snippets statt Slots.
Häufige Anfänger-Fehler
Komponente kleingeschrieben verwendet.
<greeting /> wird als HTML-Tag interpretiert. Immer <Greeting />.
let count = 0; ohne $state(...).
Funktioniert beim ersten Render, aber Updates lösen kein Re-Render aus. In Svelte 5 ist $state Pflicht für reaktive Werte.
on:click statt onclick.
Funktioniert in Svelte 5 nur im Legacy-Modus. Neuer Code nutzt direkt onclick={...}.
Vergessenes {@render children()}.
Der Snippet wird nicht automatisch ausgegeben — der @render-Aufruf ist zwingend.
Default-Export oder benannter Export erwartet.
.svelte-Dateien haben immer einen Default-Export, der die Komponente selbst ist. import Greeting from '...' reicht.