π Svelte Component Props: The Gift-Giving Guide
Imagine components are like friends at a birthday party. Props are the gifts you give them to make them special!
π The Big Picture
Every Svelte component can receive props β special pieces of information passed from a parent component. Think of it like this:
- Parent Component = You (the gift giver)
- Child Component = Your friend (the gift receiver)
- Props = The gifts you bring!
Without props, every component would be identical and boring. Props make each one unique!
π¦ Declaring Props
What is it?
Telling your component: βHey, Iβm expecting a gift!β
The Simple Way
In Svelte 5, we use the $props() rune to declare what gifts we expect:
<script>
let { name } = $props();
</script>
<p>Hello, {name}!</p>
Real-Life Example
Imagine a greeting card component. It needs to know WHO to greet:
<!-- GreetingCard.svelte -->
<script>
let { recipientName } = $props();
</script>
<div class="card">
Dear {recipientName},
Happy Birthday! π
</div>
Using it:
<GreetingCard recipientName="Sarah" />
Result: βDear Sarah, Happy Birthday! πβ
π Default Prop Values
What is it?
Sometimes your friend forgets to bring a gift. No problem! You can set a backup gift (default value).
How it works
<script>
let { color = "blue" } = $props();
</script>
<div style="background: {color}">
I'm {color}!
</div>
If someone uses <MyBox /> without a color prop, itβs blue!
If they use <MyBox color="red" />, itβs red!
Think of it likeβ¦
A pizza order form:
- Default size = Medium
- Default crust = Regular
- You only change what you want different!
<script>
let {
size = "medium",
crust = "regular",
toppings = ["cheese"]
} = $props();
</script>
β¨ The $props Rune
What is a Rune?
Runes are special Svelte 5 keywords that start with $. Theyβre like magic spells that give your code superpowers!
$props() β The Gift Receiver Spell
<script>
// πͺ This magic spell receives all gifts!
let { title, count, isActive } = $props();
</script>
Why is it special?
- Clean syntax β One line declares everything
- Destructuring β Pick exactly what you need
- Type-friendly β Works great with TypeScript
Multiple Props Example
<script>
let {
username,
score = 0,
level = 1,
isOnline = false
} = $props();
</script>
<div class="player-card">
<h3>{username}</h3>
<p>Score: {score}</p>
<p>Level: {level}</p>
<span>{isOnline ? 'π’' : 'β«'}</span>
</div>
π The $bindable Rune
What is it?
Normal props are like giving a photo β your friend can look but canβt change the original. $bindable is like giving a shared notebook β changes go both ways!
The Magic of Two-Way Binding
<!-- Parent.svelte -->
<script>
let userName = "Alex";
</script>
<ChildInput bind:value={userName} />
<p>Parent sees: {userName}</p>
<!-- ChildInput.svelte -->
<script>
let { value = $bindable() } = $props();
</script>
<input bind:value />
How it works
graph TD A[Parent: userName = Alex] -->|passes down| B[Child: value] B -->|user types Ben| C[Child updates value] C -->|$bindable syncs back| D[Parent: userName = Ben]
Real Example: A Counter
<!-- Parent -->
<script>
let count = 0;
</script>
<Counter bind:count />
<p>Count is: {count}</p>
<!-- Counter.svelte -->
<script>
let { count = $bindable(0) } = $props();
</script>
<button onclick={() => count++}>
Add One ({count})
</button>
Click the button in the child β parentβs count updates too!
β‘ Prop Reactivity
What is it?
When a prop changes, your component automatically updates. Like magic!
The Flow
graph TD A[Parent changes prop] --> B[Svelte detects change] B --> C[Child re-renders] C --> D[User sees update instantly]
Example: Live Score
<!-- Parent -->
<script>
let score = 0;
</script>
<button onclick={() => score++}>
Goal! β½
</button>
<Scoreboard currentScore={score} />
<!-- Scoreboard.svelte -->
<script>
let { currentScore } = $props();
</script>
<div class="board">
SCORE: {currentScore}
</div>
Every time you click βGoal!β, the scoreboard updates automatically!
Important Rule
Props flow downward like a waterfall:
- Parent β Child β
- Child β Parent β (unless using
$bindable)
π Spread Props
What is it?
Instead of passing props one by one, spread them all at once! Like dumping a whole bag of gifts.
The Problem It Solves
Without spread (tedious):
<UserCard
name={user.name}
age={user.age}
email={user.email}
avatar={user.avatar}
bio={user.bio}
/>
With spread (elegant):
<UserCard {...user} />
How It Works
<script>
let buttonProps = {
disabled: false,
type: "submit",
class: "primary"
};
</script>
<!-- These are the same! -->
<button {...buttonProps}>Click</button>
<button
disabled={false}
type="submit"
class="primary"
>Click</button>
Combining Spread with Extras
<script>
let baseStyles = { color: "blue" };
</script>
<!-- Spread + override -->
<Box {...baseStyles} color="red" />
The color will be βredβ because explicit props override spread!
π§© Object Destructuring in Props
What is it?
Unpacking a gift box to grab exactly what you want inside!
Basic Destructuring
<script>
// Instead of: let props = $props();
// We destructure directly:
let { name, age, city } = $props();
</script>
With Defaults
<script>
let {
title = "Untitled",
items = [],
showHeader = true
} = $props();
</script>
Nested Destructuring
When a prop is an object itself:
<script>
let {
user: { name, email } = {}
} = $props();
</script>
<p>{name} ({email})</p>
Renaming While Destructuring
<script>
// Prop comes as "data", we call it "items"
let { data: items = [] } = $props();
</script>
{#each items as item}
<li>{item}</li>
{/each}
π Rest Props Pattern
What is it?
Grab some specific gifts, then put everything else in a βrestβ bag!
The Syntax
<script>
let { name, age, ...rest } = $props();
</script>
nameandage= specific props you want...rest= everything else bundled together
Why Use It?
Perfect for wrapper components!
<!-- CustomButton.svelte -->
<script>
let { variant = "primary", ...rest } = $props();
</script>
<button
class="btn btn-{variant}"
{...rest}
>
<slot />
</button>
Using it:
<CustomButton
variant="danger"
disabled
onclick={handleClick}
aria-label="Delete"
>
Delete
</CustomButton>
The variant is used for styling. Everything else (disabled, onclick, aria-label) passes through to the actual <button>!
Real-World Pattern
<!-- Input.svelte -->
<script>
let {
label,
error,
...inputProps
} = $props();
</script>
<div class="form-field">
<label>{label}</label>
<input {...inputProps} />
{#if error}
<span class="error">{error}</span>
{/if}
</div>
<!-- Usage -->
<Input
label="Email"
type="email"
placeholder="you@example.com"
required
error={emailError}
/>
π― Quick Reference
| Pattern | Use Case |
|---|---|
let { x } = $props() |
Basic prop declaration |
let { x = 5 } = $props() |
Prop with default |
let { x = $bindable() } = $props() |
Two-way binding |
<Child {...obj} /> |
Spread all props |
let { a, ...rest } = $props() |
Rest pattern |
π You Did It!
You now understand the 8 key patterns for Svelte component props:
- β Declaring Props β Tell components what to expect
- β Default Values β Set fallbacks for missing props
- β $props Rune β The magic spell to receive props
- β $bindable Rune β Enable two-way communication
- β Prop Reactivity β Automatic updates when props change
- β Spread Props β Pass many props at once
- β Object Destructuring β Pick exactly what you need
- β Rest Props β Capture the leftovers
Props are the secret sauce that makes Svelte components flexible and reusable. Now go build something amazing! π
