Svelte Component Communication
Learn how Svelte components communicate through props, events, slots, and context:
Props - Parent to Child
<!-- Child.svelte -->
<script>
// Declare props with export
export let title;
export let count = 0; // With default value
export let user = null; // Optional prop
// Props are reactive
$: console.log('Title changed:', title);
</script>
<div>
<h2>{title}</h2>
<p>Count: {count}</p>
{#if user}
<p>User: {user.name}</p>
{/if}
</div>
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let parentTitle = 'Hello';
let parentCount = 5;
let currentUser = { name: 'John' };
</script>
<Child title={parentTitle} count={parentCount} user={currentUser} />
<!-- Shorthand when variable name matches prop name -->
<Child {title} {count} {user} />Events - Child to Parent
<!-- Child.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function sendMessage() {
dispatch('message', {
text: 'Hello from child'
});
}
function increment() {
dispatch('increment', { value: 1 });
}
</script>
<button on:click={sendMessage}>Send Message</button>
<button on:click={increment}>Increment</button>
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let count = 0;
let lastMessage = '';
function handleMessage(event) {
lastMessage = event.detail.text;
}
function handleIncrement(event) {
count += event.detail.value;
}
</script>
<Child on:message={handleMessage} on:increment={handleIncrement} />
<p>Count: {count}</p>
<p>Last message: {lastMessage}</p>Two-Way Binding (bind:)
<!-- Child.svelte -->
<script>
export let value;
</script>
<input type="text" bind:value />
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let searchQuery = '';
</script>
<!-- Two-way binding -->
<Child bind:value={searchQuery} />
<p>You typed: {searchQuery}</p>Slots - Content Projection
<!-- Card.svelte -->
<div class="card">
<header>
<slot name="header">Default Header</slot>
</header>
<main>
<slot>Default content</slot>
</main>
<footer>
<slot name="footer" />
</footer>
</div>
<!-- Usage -->
<script>
import Card from './Card.svelte';
</script>
<Card>
<h2 slot="header">Card Title</h2>
<!-- Default slot -->
<p>This is the main content.</p>
<div slot="footer">
<button>Cancel</button>
<button>Save</button>
</div>
</Card>
<!-- Slot props - pass data to parent -->
<!-- List.svelte -->
<script>
export let items = [];
</script>
{#each items as item, index}
<slot {item} {index}>
<!-- Fallback content -->
<p>{item.name}</p>
</slot>
{/each}
<!-- Parent usage -->
<List {items} let:item let:index>
<div>
<strong>{index + 1}.</strong>
<span>{item.name}</span>
<span>${item.price}</span>
</div>
</List>Context API
<!-- Parent.svelte -->
<script>
import { setContext } from 'svelte';
import Child from './Child.svelte';
const theme = {
color: 'blue',
background: 'white'
};
setContext('theme', theme);
// Can also use writable store
import { writable } from 'svelte/store';
const user = writable({ name: 'John' });
setContext('user', user);
</script>
<Child />
<!-- Child.svelte (any level deep) -->
<script>
import { getContext } from 'svelte';
const theme = getContext('theme');
const user = getContext('user');
</script>
<div style="color: {theme.color}; background: {theme.background}">
<p>User: {$user.name}</p>
</div>Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free