Komponenten sind in Svelte das zentrale Strukturprinzip — jede .svelte-Datei ist eine eigene Komponente, die einen klar abgegrenzten Teil der Benutzeroberfläche kapselt. Dieser Artikel klärt, was Komponenten in Svelte ausmacht, wie du sie nutzt und auf welche Konventionen du achten solltest. Wer das Konzept einmal verinnerlicht hat, baut Anwendungen wie aus Lego — wiederverwendbar, isoliert und testbar.

Was ist eine Svelte-Komponente?

Eine Komponente ist eine .svelte-Datei mit Markup, optionaler Logik (<script>) und optionalem Style. Sie wird in andere Komponenten oder Routen importiert und wie ein HTML-Tag verwendet — mit großem Anfangsbuchstaben, damit der Compiler sie von HTML-Elementen unterscheiden kann.

Drei Eigenschaften jeder Komponente:

  • Gekapselt: Styles greifen per Default nur in der Komponente, State lebt lokal.
  • Wiederverwendbar: Eine einmal geschriebene Komponente lässt sich mit unterschiedlichen Props mehrfach instanziieren.
  • Komposierbar: Komponenten verschachteln sich beliebig — Anwendungen entstehen durch Komposition, nicht durch Vererbung.

Komponente schreiben

svelte src/lib/components/Greeting.svelte
<script>
    let { name = 'Welt' } = $props();
</script>

<p class="greeting">Hallo, {name}!</p>

<style>
    .greeting {
        font-weight: 600;
    }
</style>

Die Komponente nimmt einen optionalen Prop name, hat ein einfaches Markup und eigenes Styling.

Komponente verwenden

Im Eltern-Element importiert und wie ein Tag eingesetzt:

svelte src/routes/+page.svelte
<script>
    import Greeting from '$lib/components/Greeting.svelte';
</script>

<Greeting name="Anna" />
<Greeting name="Bernd" />
<Greeting />

Drei wichtige Punkte:

  • Default-Export: .svelte-Dateien exportieren ihre Komponente als Default — import Greeting from ... ist die kanonische Form.
  • $lib-Alias: SvelteKit-Projekte verlinken $lib auf src/lib/. Imports werden dadurch unabhängig von der relativen Pfadtiefe.
  • Selbst-schließendes Tag: Komponenten ohne Children werden als <Greeting /> (mit Schrägstrich) geschrieben.

Naming-Konventionen

Etablierte Konventionen im Svelte-Ökosystem:

  • Datei und Komponente in PascalCase: UserCard.svelte, <UserCard />.
  • Eine Komponente pro Datei. Hilfs-Komponenten in eigene Dateien.
  • Beschreibender Name, kein „MyButton” — lieber PrimaryButton oder einfach Button.
  • Kein Component-Suffix: <UserCard /> statt <UserCardComponent />.

Häufige Ablage-Strukturen:

text Variante 1: Flach
src/lib/components/
  Button.svelte
  Card.svelte
  Modal.svelte
  UserCard.svelte
text Variante 2: Gruppiert
src/lib/components/
  ui/
    Button.svelte
    Card.svelte
    Modal.svelte
  domain/
    UserCard.svelte
    ProductRow.svelte

Beide sind valide. Bei kleinen Apps reicht „flach”, bei größeren lohnt die Trennung zwischen generischer UI und domänenspezifischen Komponenten.

Komponente vs. Instanz

Wichtig zu unterscheiden:

  • Komponente = die Definition in der Datei. Wird einmal pro Datei geschrieben und kompiliert.
  • Instanz = jede Verwendung im Markup. Pro <Greeting />-Tag entsteht eine eigene Instanz mit eigenem State.
svelte Drei Instanzen, gemeinsame Komponente
<Counter />
<Counter />
<Counter />

Drei Counter — jeder mit eigenem State. Der Code der Counter-Komponente liegt nur einmal im Bundle.

Wann eine neue Komponente?

Heuristiken:

  • Klar abgegrenzte UI-Aufgabe. „Zeigt einen einzelnen Eintrag” — Komponente.
  • Wiederholung. Wenn dasselbe Markup zweimal auftaucht, lohnt eine Komponente.
  • Eigener State. Sobald ein Bereich eigenen lokalen State hält (Toggle, Filter, Eingabe), ist die Komponenten-Grenze natürlich.
  • Lesbarkeit. Wenn eine Datei länger als 200 Zeilen wird, ist Aufteilen meistens sinnvoll.

Anti-Patterns:

  • Verfrühte Abstraktion. Eine Komponente, weil „könnte man später wiederverwenden”, ist oft Ballast.
  • Zu kleinteilig. <Heading> als eigene Komponente, die nur ein <h1> rendert, ist meist überflüssig.
  • Komponente als „Ordnungsmittel”. Wenn die Aufteilung nur den Code „kürzer” macht, ohne klare Verantwortung, sind die Grenzen oft falsch gewählt.

Praktisches Beispiel: UI auseinanderbauen

Eine Profil-Seite, monolithisch:

svelte − Alles in einer Datei
<main>
    <header>
        <img src={user.avatar} alt={user.name} />
        <div>
            <h1>{user.name}</h1>
            <p>{user.bio}</p>
        </div>
    </header>

    <ul>
        {#each user.posts as post}
            <li>
                <h2>{post.title}</h2>
                <p>{post.excerpt}</p>
                <small>{post.date}</small>
            </li>
        {/each}
    </ul>
</main>

Sinnvolle Aufteilung in drei Komponenten:

svelte + Aufgeteilt
<script>
    import UserHeader from '$lib/components/UserHeader.svelte';
    import PostList from '$lib/components/PostList.svelte';

    let { user } = $props();
</script>

<main>
    <UserHeader {user} />
    <PostList posts={user.posts} />
</main>

UserHeader und PostList sind isoliert testbar, lassen sich auf anderen Seiten wiederverwenden und reduzieren die Komplexität jedes einzelnen Files.

Häufige Stolperfallen

Komponente kleingeschrieben verwendet. <greeting /> interpretiert Svelte als HTML-Tag — kein Fehler, aber auch keine Komponente.

Vergessener Import. <UserCard /> ohne import UserCard from '...' wird als unbekanntes HTML-Element behandelt. Der Svelte-Compiler warnt im Dev-Modus.

Datei-Endung beim Import. import App from './App.svelte'; — die .svelte-Endung gehört zwingend dazu.

Component-Library ohne Default-Export. Bei selbst gebauten UI-Bibliotheken passiert es, dass Komponenten nur als named Export verfügbar sind. Üblich: aus Lib-Index re-exportieren, dann in der App import { Button } from '$lib/ui';.

Zu viele Props. Wenn eine Komponente zehn oder mehr Props braucht, ist meist die Verantwortung nicht klar genug. Aufteilen oder Konfiguration als Objekt-Prop bündeln.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Components

Zur Übersicht