Props are how components are configured and composed; every reusable component has them.
Components receive inputs as props. Inside the child, read them with the `$props` rune and destructure:
let { title, count = 0, ...rest } = $props();- Default values use normal destructuring defaults (
count = 0), applied when the parent passesundefined. - Rename with
{ class: klass }, useful for reserved words. ...restcollects everything else, handy for forwarding attributes to an element:<button {...rest}>.- With TypeScript, annotate:
let { title, count = 0 }: { title: string; count?: number } = $props();.
The parent passes props as attributes: <Counter title="Clicks" count={5} />, {title} shorthand when the variable has the same name, and {...obj} to spread an object.
Props are reactive: when the parent changes the value, destructured variables update too (the compiler makes this work). They are not meant to be reassigned by the child. You can temporarily reassign a prop locally (it will be overwritten when the parent passes a new value), but mutating an object prop the child doesn't own triggers a dev warning (ownership_invalid_mutation). To let a child change parent state, pass a callback prop or use a bindable prop (later lessons).
Every prop is optional unless typed otherwise; missing ones are undefined. $props.id() (5.20+) generates an id unique to the component instance, consistent between server and client, for for/id pairs.
Example
<!-- Badge.svelte -->
<script>
let { label, tone = 'info', count = 0, ...rest } = $props();
</script>
<span class="badge {tone}" {...rest}>
{label}{#if count > 0}<b> {count}</b>{/if}
</span>
<!-- App.svelte -->
<script>
import Badge from './Badge.svelte';
let unread = $state(3);
let label = 'Inbox';
</script>
<Badge {label} count={unread} title="Unread messages" /> <!-- title goes via rest -->
<Badge label="Spam" tone="warn" /> <!-- count defaults to 0 -->
<button onclick={() => unread++}>new mail</button>Remember
let { a, b = default, ...rest } = $props()reads props- Destructured props stay reactive to parent changes
- Don't mutate props you don't own; use callbacks or bindable props
Watch out for
- Mutating an object prop in the child to communicate with the parent; it's a dev warning and makes data flow hard to follow.