S SvelteKurs
M1 · Svelte-Komponenten

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.
Gruss.svelte svelte
<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.

svelte
<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.

svelte
<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.

svelte
<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:

  1. <script module> (falls vorhanden)
  2. <script> (die Instanz-Logik)
  3. das Markup
  4. <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.
Zaehler.svelte svelte
<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.

show.html.erb ruby
<%# 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:

▶ Live-Gruß · Interaktiv

Bitte gib deinen Namen ein.

So sieht der Code hinter dieser Demo aus:

Gruss.svelte svelte
<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.