Props (Properties) sind der Standardweg, um Daten von der Eltern-Komponente an die Kind-Komponente weiterzureichen. Im <script> der Kind-Komponente liest man sie mit der $props()-Rune, beim Aufruf werden sie wie HTML-Attribute übergeben. Dieser Artikel deckt die praktische Verwendung ab — von der einfachsten Übergabe bis zu Rest-Props, Spread-Aufrufen und der Migration aus Svelte 4.
Props deklarieren
Im Kind:
<script>
let { name, age } = $props();
</script>
<p>{name}, {age} Jahre</p>Im Eltern:
<Greeting name="Anna" age={30} />- Strings kommen mit Anführungszeichen:
name="Anna". - Andere Werte (Zahlen, Booleans, Variablen, Objekte) in geschweiften Klammern:
age={30},user={currentUser}.
Shorthand
Wenn der Variablen-Name im Eltern-Komponent gleich dem Prop-Namen ist, gibt es eine Kurzform:
<UserCard user={user} count={count} /><UserCard {user} {count} />Identisch zur ES-Module-Property-Shorthand-Syntax. Beim großflächigen Weiterreichen spart das viel Schreibarbeit.
Defaults
Defaults werden in der Destrukturierung gesetzt:
<script>
let {
name = 'Welt',
greeting = 'Hallo',
showAvatar = false,
} = $props();
</script>
<p>{greeting}, {name}!</p>
{#if showAvatar}<Avatar />{/if}Wichtig: Defaults greifen nur, wenn die Prop nicht übergeben wird (oder undefined ist). null als expliziter Wert greift den Default nicht.
Rest-Props
Bei Wrapper-Komponenten will man oft alle nicht-konsumierten Props an das innere Element weiterreichen:
<script>
let { variant = 'default', children, ...rest } = $props();
</script>
<button class={`btn btn-${variant}`} {...rest}>
{@render children()}
</button><StyledButton
variant="primary"
type="submit"
disabled={loading}
onclick={save}
aria-label="Eintrag speichern"
>
Speichern
</StyledButton>type, disabled, onclick und aria-label landen über {...rest} direkt am <button>. Diese Pattern macht Wrapper-Komponenten transparent — alle nativen Attribute funktionieren wie gewohnt.
Spread beim Aufruf
Auch beim Aufrufen einer Komponente kann ein Objekt gespreaded werden:
<script>
const props = {
name: 'Anna',
age: 30,
role: 'admin',
};
</script>
<UserCard {...props} />Praktisch, wenn Props aus einer Datenstruktur kommen — z. B. nach einem Fetch.
TypeScript-Typen
Mit lang="ts" lassen sich Props strukturiert typisieren:
<script lang="ts">
type Props = {
name: string;
age?: number;
role?: 'admin' | 'user' | 'guest';
onSelect?: (id: string) => void;
};
let { name, age, role = 'user', onSelect }: Props = $props();
</script>- Pflicht-Props ohne
?. - Optionale Props mit
?. - Union-Types für enumartige Werte (
'admin' | 'user' | 'guest').
Tieferes zu Snippet-Typen und Generic Components im Artikel TypeScript mit Svelte.
Pflicht- vs. Optional-Props
In TypeScript-Code wird die Pflicht-Eigenschaft über den Type abgebildet — fehlende Pflicht-Props werden zur Compile-Zeit angemerkt:
<script lang="ts">
type Props = {
userId: string; // Pflicht
};
let { userId }: Props = $props();
</script>Beim Aufruf ohne userId zeigt die IDE einen Fehler. In reinem JavaScript gibt es diesen Schutz nicht — dann hilft eine Laufzeit-Prüfung im Effekt:
<script>
let { userId } = $props();
$effect(() => {
if (!userId) {
console.error('userId ist Pflicht');
}
});
</script>Read-only und Mutation
Props sind innerhalb der Kind-Komponente nicht überschreibbar:
let { count } = $props();
count = 10; // Compiler-WarnungSoll der Wert sich ändern können, gibt es zwei Wege:
- Lokale Kopie mit
$state(initialValue), falls Updates nicht zurück sollen. $bindable(...)für echte Two-Way-Bindings — siehe$bindable.
Bei Objekt- oder Array-Props können tiefe Mutationen funktionieren, sind aber konzeptuell nicht sauber — sie verändern den State des Eltern-Komponenten ohne dessen Wissen. Besser ist es, eine Callback-Prop zu nutzen, die den Eltern-Komponent informiert.
Häufige Stolperfallen
Boolean-Props.
<!-- Beide gleichbedeutend -->
<Modal open />
<Modal open={true} />Das ist Standard-HTML-Verhalten — auch Komponenten interpretieren attr ohne Wert als attr={true}.
Reaktivität durch Destrukturierung verlieren.
const { name } = props; (außerhalb von $props()) extrahiert den aktuellen Wert und ist nicht mehr reaktiv.
Numerische Strings.
<Counter initial="5" /> <!-- "5" als String! -->In den geschweiften Klammern {5} schreiben oder explizit casten.
Spread mit Konflikten.
<button {...rest} class="btn"><!-- class wins --></button>
<button class="btn" {...rest}><!-- rest.class wins (falls gesetzt) --></button>