Svelte and SvelteKit course Β· Module 4: Props and Events
Context API
In this lesson5
For deeply nested components, the Context API lets you avoid "prop drilling".
Problem: Prop Drilling
App
βββ Layout
βββ Sidebar
βββ Navigation
βββ NavItem <-- needs data from App!Passing props through every level is cumbersome.
Solution: Context
<!-- App.svelte -->
<script>
import { setContext } from 'svelte';
import Layout from './Layout.svelte';
const user = $state({
name: 'Ragnar',
role: 'jarl',
gold: 1000
});
// Set context - available to all descendants
setContext('user', user);
</script>
<Layout />
<button onclick={() => user.gold += 100}>+100 gold</button><!-- NavItem.svelte (deeply nested) -->
<script>
import { getContext } from 'svelte';
// Get context - works at any level!
const user = getContext('user');
</script>
<div class="nav-item">
<span>{user.name}</span>
<span>({user.role}, {user.gold} gold)</span>
</div>The context holds a $state object, so descendants see its changes. Change its fields (user.gold += 100) instead of assigning a new object - otherwise descendants keep the old one.
Typed Context
It pays to keep context keys and their functions in one file. Since Svelte 5.40 createContext does this for you - it returns a pair of functions, with no manual key:
// context.ts
import { createContext } from 'svelte';
interface User {
name: string;
role: string;
}
export const [getUserContext, setUserContext] = createContext<User>();In older versions of Svelte 5 you write the same with setContext and getContext and a unique key:
// context.js
import { getContext, setContext } from 'svelte';
const USER_KEY = Symbol('user');
export function setUserContext(user) {
setContext(USER_KEY, user);
}
export function getUserContext() {
return getContext(USER_KEY);
}<!-- App.svelte -->
<script>
import { setUserContext } from './context.js';
const user = $state({ name: 'Ragnar', role: 'jarl' });
setUserContext(user);
</script><!-- DeepChild.svelte -->
<script>
import { getUserContext } from './context.js';
const user = getUserContext();
</script>
<p>{user.name}</p>Context vs Props vs Global State
| Method | When to use |
|---|---|
| Props | Direct parent-child |
| Context | Deep hierarchy, per-tree data |
| Global state | $state in a .svelte.js file or stores (module 8), multiple component trees |
Example: Theme Context
<!-- ThemeProvider.svelte -->
<script>
import { setContext } from 'svelte';
let { children } = $props();
let theme = $state('dark');
setContext('theme', {
get current() { return theme; },
toggle() { theme = theme === 'dark' ? 'light' : 'dark'; }
});
</script>
<div class="theme-{theme}">
{@render children()}
</div><!-- ThemedButton.svelte -->
<script>
import { getContext } from 'svelte';
const theme = getContext('theme');
</script>
<button class={theme.current} onclick={theme.toggle}>
Change theme ({theme.current})
</button>The current getter always returns the latest value of theme, so the button refreshes after every theme change.
Context is like secret passages in the palace of Asgard - data flows without obstacles!
Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. When should you use the Context API instead of props?
2. Which functions from the svelte package set and get a context by key?
Hands-on tasks in the game
- Click in order
When to use each: props (direct), context (deep), global state (stores or .svelte.js)