Skip to main content
Svelte Fundamentals
CHAPTER 09 Beginner

Props and Component Communication

Updated: May 18, 2026
5 min read

# CHAPTER 9

Props and Component Communication

1. Chapter Introduction

Components become truly powerful when they can talk to each other. In Svelte, data flows down via props (export let), and events flow up via createEventDispatcher or bind: for two-way binding. This chapter covers the complete Svelte component communication model.

2. Learning Objectives

  • Pass data from parent to child using export let.
  • Dispatch custom events from child to parent.
  • Use bind: for two-way prop binding.
  • Spread props using {...object}.
  • Build a multi-component architecture.

3. Passing Props (Parent → Child)

svelte
123456789101112131415161718192021
<!-- ProductCard.svelte -->
<script>
  export let name;
  export let price;
  export let category = &#039;General'; // Default value
  export let inStock = true;

  // Computed from props
  $: formattedPrice = `$${price.toLocaleString()}`;
</script>

<div class="card" class:out-of-stock={!inStock}>
  <span class="badge">{category}</span>
  <h3>{name}</h3>
  <p>{formattedPrice}</p>
  {#if inStock}
    <button on:click>Add to Cart</button>
  {:else}
    <span>Out of Stock</span>
  {/if}
</div>
svelte
12345678910111213
<!-- Parent -->
<script>
  import ProductCard from &#039;./ProductCard.svelte';
  let products = [
    { id: 1, name: &#039;Laptop', price: 999, category: 'Electronics', inStock: true },
    { id: 2, name: &#039;Mouse', price: 49, inStock: false }
  ];
</script>

{#each products as product (product.id)}
  <!-- Spread props with {...product} instead of listing each -->
  <ProductCard {...product} />
{/each}

4. Child-to-Parent: Events

svelte
123456789101112131415
<!-- CartItem.svelte -->
<script>
  import { createEventDispatcher } from &#039;svelte';
  export let item;

  const dispatch = createEventDispatcher();
</script>

<div class="item">
  <span>{item.name}</span>
  <span>${item.price}</span>
  <button on:click={() => dispatch(&#039;remove', { id: item.id })}>Remove</button>
  <button on:click={() => dispatch(&#039;increase', { id: item.id })}>+</button>
  <button on:click={() => dispatch(&#039;decrease', { id: item.id })}>-</button>
</div>
svelte
12345678910111213141516171819
<!-- Parent Cart -->
<script>
  import CartItem from &#039;./CartItem.svelte';
  let cart = [
    { id: 1, name: &#039;Laptop', price: 999, qty: 1 }
  ];

  function handleRemove(e) {
    cart = cart.filter(i => i.id !== e.detail.id);
  }
</script>

{#each cart as item (item.id)}
  <CartItem {item}
    on:remove={handleRemove}
    on:increase={e => cart = cart.map(i => i.id === e.detail.id ? {...i, qty: i.qty+1} : i)}
    on:decrease={e => cart = cart.map(i => i.id === e.detail.id ? {...i, qty: Math.max(1,i.qty-1)} : i)}
  />
{/each}

5. Two-Way Binding with bind:

svelte
12345678
<!-- NumberInput.svelte -->
<script>
  export let value = 0;
  export let min = 0;
  export let max = 100;
</script>

<input type="number" bind:value {min} {max} />
svelte
123456789
<!-- Parent using two-way binding -->
<script>
  import NumberInput from &#039;./NumberInput.svelte';
  let quantity = 1;
</script>

<!-- bind: makes the binding two-way! -->
<NumberInput bind:value={quantity} min={1} max={10} />
<p>Quantity: {quantity}</p>

6. Event Forwarding

To forward native DOM events from a child to the parent, use on:click without a handler:
svelte
1234
<!-- Button.svelte -->
<button on:click class:primary={variant === &#039;primary'} {...$$restProps}>
  <slot />
</button>
svelte
12
<!-- Parent -->
<Button on:click={handleClick} variant="primary">Save</Button>

7. Spread Props ($$props and $$restProps)

svelte
12345678910
<!-- Input.svelte — passes all unrecognized props to the underlying input -->
<script>
  export let label;
  export let value;
</script>

<label>
  {label}
  <input bind:value {...$$restProps} />
</label>
svelte
12
<!-- Usage -->
<Input label="Email" bind:value={email} type="email" placeholder="Enter email" required />

8. Common Mistakes

  • Mutating props in the child: Never modify an export let prop inside the child. Use bind: for two-way or dispatch an event for the parent to handle.
  • Forgetting export: let name is private local state. export let name is a prop.

9. MCQs

Question 1

How do you declare a prop in Svelte?

Question 2

How do you set a default prop value?

Question 3

What is the data flow direction for props?

Question 4

What Svelte function enables custom event dispatching?

Question 5

How do you access dispatched event data in the parent?

Question 6

What does bind:value={quantity} on a child component do?

Question 7

What does {...product} do when used on a component?

Question 8

What is $$restProps?

Question 9

How do you forward a click event from a child <button> to the parent without a handler?

Q10. Should you mutate a prop inside a child component? a) Yes b) No — dispatch an event or use bind: for two-way data — Answer: b

10. Interview Questions

  • Q: Compare Svelte's prop/event pattern with Angular's @Input/@Output.
  • Q: When would you use bind: instead of on:dispatch?

11. Summary

Svelte's component communication is elegant: export let for props flowing down, createEventDispatcher for events flowing up, and bind: for convenient two-way binding. The $$restProps pattern enables building truly generic, flexible components that forward all HTML attributes.

12. Next Chapter Recommendation

When state needs to be shared across many components that have no direct relationship, local state and prop-drilling break down. In Chapter 10: Svelte Stores, we learn a global state solution built right into Svelte.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·