Share state across components the right way — lift state to a common parent, two-way bind with $bindable, context for app-wide values, and shared stores in .svelte.ts modules.
Why: when two siblings need the same data, the state moves to their closest common parent — one owns it, both receive it. The child gets the value as a prop and reports changes up through a callback prop. This is the first tool to reach for; most "state management" problems dissolve right here.
<!-- src/lib/components/FilterBox.svelte — reports changes up -->
<script lang="ts">
let {
value,
onchange,
}: { value: string; onchange: (v: string) => void } = $props()
</script>
<input {value} oninput={(e) => onchange(e.currentTarget.value)} />
<!-- src/routes/+page.svelte — both siblings need query,
so the parent owns it -->
<script lang="ts">
import FilterBox from '$lib/components/FilterBox.svelte'
let query = $state('')
</script>
<FilterBox value={query} onchange={(v) => (query = v)} />
<p>Results for: {query || '(everything)'}</p>Why: the prop-down/callback-up dance from the last topic is so common that Svelte gives it one line: mark a prop $bindable and the parent can connect with bind: — changes flow both ways, exactly like binding an input.
<!-- src/lib/components/SearchInput.svelte -->
<script lang="ts">
// $bindable = a prop the CHILD may write back to the parent
let { value = $bindable('') }: { value?: string } = $props()
</script>
<input bind:value placeholder="Search…" />
<!-- In the parent:
let query = $state('')
<SearchInput bind:value={query} />
<p>Searching for: {query}</p> -->Why: context delivers a value to any component below the one that set it, without threading it through every layer of props. setContext during component setup, getContext anywhere beneath. When: values the whole tree needs but that rarely change — the signed-in user, theme, locale. Note: pass a $state object so changes stay reactive.
<!-- src/routes/+layout.svelte — set once near the top of the tree -->
<script lang="ts">
import { setContext } from 'svelte'
let { children } = $props()
// A $state OBJECT stays reactive when read through context
const theme = $state({ current: 'dark' })
setContext('theme', theme)
</script>
{@render children()}
<!-- Any component below, no matter how deep -->
<script lang="ts">
import { getContext } from 'svelte'
const theme = getContext<{ current: string }>('theme')
</script>
<p>Current theme: {theme.current}</p>
<button
onclick={() => (theme.current = theme.current === 'dark' ? 'light' : 'dark')}
>
Toggle theme
</button>