Skip to main content
Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app. In Svelte, component props can be bound, which means that data can also flow up from child to parent. This isn’t something you should do often — overuse can make your data flow unpredictable and your components harder to maintain — but it can simplify your code if used sparingly and carefully. It also means that a state proxy can be mutated in the child.

Signature

function $bindable<T>(fallback?: T): T;
fallback
T
The fallback value to use when the parent component doesn’t bind to this prop.
Mutation is also possible with normal props, but is strongly discouraged — Svelte will warn you if it detects that a component is mutating state it does not ‘own’.

Basic usage

To mark a prop as bindable, we use the $bindable rune:
/// file: FancyInput.svelte
<script>
	let { value = $bindable(), ...props } = $props();
</script>

<input bind:value={value} {...props} />

<style>
	input {
		font-family: 'Comic Sans MS';
		color: deeppink;
	}
</style>
Now, a component that uses <FancyInput> can add the bind: directive:
/// file: App.svelte
<script>
	import FancyInput from './FancyInput.svelte';

	let message = $state('hello');
</script>

<FancyInput bind:value={message} />
<p>{message}</p>
The parent component doesn’t have to use bind: — it can just pass a normal prop. Some parents don’t want to listen to what their children have to say.

Fallback values

In this case, you can specify a fallback value for when no prop is passed at all:
/// file: FancyInput.svelte
let { value = $bindable('fallback'), ...props } = $props();

Two-way binding

When a parent component binds to a child prop using bind:value={message}, changes in the child will flow back up to the parent. This creates a two-way binding:
  • Parent changes update the child
  • Child changes update the parent
<script>
	import Child from './Child.svelte';
	let count = $state(0);
</script>

<Child bind:count={count} />
<p>Parent count: {count}</p>

When to use bindable props

Use $bindable sparingly. It’s most appropriate for:
  • Form input wrappers (like the FancyInput example)
  • Tightly coupled components where bidirectional data flow is natural
  • Creating reusable components that need to update parent state
For most component communication, prefer:
  • Passing data down via props
  • Passing callbacks up via event handler props
  • Using context for deeply nested components
Overusing $bindable can make data flow harder to understand and debug. Use it judiciously.