Anatomie einer Komponente
Jede .svelte-Datei besteht aus drei klar getrennten Teilen: Logik, Markup und Style — alles an einem Ort, aber sauber abgegrenzt.
Drei Teile, eine Datei
Eine Svelte-Komponente ist eine einzelne Datei mit der Endung .svelte. Sie
bündelt drei Zuständigkeiten, die zusammengehören — die Logik, das Markup und die Styles ein und desselben UI-Bausteins:
<script lang="ts">— die Logik: Imports, reaktiver Zustand mit$state, Funktionen.- das Markup — HTML mit eingebetteten Ausdrücken in geschweiften Klammern
{ }. <style>— CSS, das standardmäßig nur für diese Komponente gilt.
<script lang="ts">
// 1) LOGIK — Imports, State, Funktionen
let name = $state('Welt');
</script>
<!-- 2) MARKUP — HTML mit Ausdrücken in { } -->
<h1>Hallo {name}!</h1>
<input bind:value={name} />
<style>
/* 3) STYLE — nur für DIESE Komponente */
h1 { color: rebeccapurple; }
</style>ℹ️ Alle drei Teile sind optional
Eine Komponente muss nicht alle drei Blöcke haben. Eine reine Darstellungs-Komponente
kommt ohne <script> aus, und viele Komponenten brauchen kein eigenes <style>. Nur eines gilt immer: Von jedem Block gibt es höchstens einen pro Datei (plus optional ein Module-Script, siehe unten).
Was gehört wohin?
Die Trennung folgt einer einfachen Faustregel: Was passiert (Logik) ist getrennt von wie es aussieht (Markup) und wie es gestaltet ist (Style).
1. Logik im <script>
Hier lebt alles, was dein JavaScript/TypeScript ausmacht: Imports anderer Komponenten, reaktiver Zustand und Funktionen, die auf Ereignisse reagieren.
<script lang="ts">
import Button from './Button.svelte';
let count = $state(0);
function erhoehen() {
count += 1;
}
</script>2. Markup: HTML mit Ausdrücken
Das Markup ist einfach HTML — angereichert um Ausdrücke in geschweiften Klammern. Auf alles
aus dem <script> kannst du hier direkt zugreifen.
<h2>Zähler</h2>
<p>Aktueller Stand: {count}</p>
<Button onclick={erhoehen}>+1</Button>3. Styles im <style>
Ganz normales CSS. Der entscheidende Unterschied: Es ist automatisch scoped — es wirkt nur innerhalb dieser Komponente und läuft nicht Gefahr, andere Teile der App zu beeinflussen. Mehr dazu in der nächsten Lektion.
<style>
h2 {
font-size: 1.5rem;
color: var(--brand);
}
</style>Reihenfolge & Konvention
Technisch ist die Reihenfolge der Blöcke Svelte egal — <style> könnte auch
oben stehen. In der Praxis hat sich aber eine feste Konvention durchgesetzt, die auch der
offizielle Formatter (Prettier mit dem Svelte-Plugin) herstellt:
<script module>(falls vorhanden)<script>(die Instanz-Logik)- das Markup
<style>
💡 Erst denken, dann zeigen, dann schmücken
Diese Reihenfolge liest sich natürlich von oben nach unten: erst die Logik, dann was damit dargestellt wird, ganz zuletzt die Optik. Halte dich daran — so findet sich jeder im Team sofort zurecht.
Das Module-Script (kurz)
Neben dem normalen <script> gibt es ein zweites, selteneres: <script module>. Der Unterschied liegt in der Lebensdauer:
- Normales
<script>läuft pro Instanz — jedes Mal, wenn die Komponente irgendwo verwendet wird, neu. <script module>läuft einmal, wenn das Modul geladen wird, und wird von allen Instanzen geteilt. Ideal für Konstanten oder gemeinsamen Zustand.
<script module lang="ts">
// Läuft EINMAL beim Laden des Moduls, nicht pro Instanz.
// Wird von allen Instanzen dieser Komponente geteilt.
let instanzenGesamt = 0;
</script>
<script lang="ts">
// Läuft für JEDE Instanz der Komponente neu.
instanzenGesamt += 1;
const meineNummer = instanzenGesamt;
</script>
<p>Ich bin Instanz Nr. {meineNummer}</p>ℹ️ Für den Anfang selten nötig
Du wirst <script module> anfangs kaum brauchen. Merke dir nur, dass es
existiert — für geteilte Werte über alle Instanzen einer Komponente hinweg. In Svelte 4 hieß
das übrigens noch <script context="module">.
Rails-Vergleich: ERB vs. Komponente
🛤️ Alles an einem Ort — aber getrennt
In Rails ist eine „Ansicht" über mehrere Orte verstreut: Die Logik gehört in den Controller
oder einen Helper, das Markup in eine .html.erb-Datei, und die Styles liegen in
der Asset Pipeline unter app/assets/stylesheets. ERB selbst vermischt dabei HTML und Ruby (<%= %>) unmittelbar ineinander.
<%# app/views/greetings/show.html.erb %>
<%# ERB mischt HTML und Ruby-Logik direkt ineinander: %>
<% name = params[:name] %>
<h1>Hallo <%= name %>!</h1>
<%# Styles liegen ganz woanders (app/assets/stylesheets),
Logik idealerweise im Controller/Helper.
Drei Dateien, drei Orte. %>Svelte dreht das um: Alle drei Teile eines Bausteins liegen in einer Datei — aber in klar abgegrenzten Blöcken statt vermischt. Du siehst auf einen Blick, was eine Komponente tut, anzeigt und wie sie aussieht, ohne zwischen drei Verzeichnissen zu springen.
Live ausprobieren
Der folgende Gruß nutzt alle drei Teile: $state in der Logik, ein bind:value und ein Ausdruck im Markup. Tippe deinen Namen:
Bitte gib deinen Namen ein.
So sieht der Code hinter dieser Demo aus:
<script lang="ts">
let name = $state('');
</script>
<input bind:value={name} placeholder="Dein Name" />
{#if name}
<p>Hallo {name}, willkommen zu Svelte!</p>
{:else}
<p>Bitte gib deinen Namen ein.</p>
{/if}Zusammenfassung
💡 Das Wichtigste
- Eine
.svelte-Datei bündelt Logik, Markup und Style in einer Einheit. <script lang="ts">für Logik, das Markup für HTML+Ausdrücke,<style>für scoped CSS.- Konventionelle Reihenfolge: Module-Script → Script → Markup → Style.
<script module>läuft einmal und wird von allen Instanzen geteilt.- Anders als ERB: alles an einem Ort, aber sauber getrennt statt vermischt.
🎯 Probier es selbst
Erweitere den Gruß-Demo: Füge im <script> ein zweites $state-Feld für einen Ort hinzu (z. B. ort) und zeige im Markup
„Hallo {name} aus {ort}!". Überlege dir, welcher Teil der Datei sich dafür ändern
muss — und welcher nicht.