Skip to content

$props and $bindable — Component Props

In React, a component declares its props via its function parameters (or TypeScript interface). Props are always one-way, read-only — the child calls a callback to ask the parent to update. Svelte 5 introduces $props() for the same one-way model, plus $bindable() for an opt-in two-way binding that eliminates the callback boilerplate.

$props() — declaring props with defaults

Section titled “$props() — declaring props with defaults”
React
// Child
function Greeting({ name = 'World', color = 'black' }) {
return <p style={{ color }}>Hello, {name}!</p>;
}
// Parent
function App() {
return <Greeting name="Alice" color="steelblue" />;
}
Svelte
<script>
let { name = 'World', color = 'black' } = $props();
</script>
<p style="color: {color}">Hello, {name}!</p>

$props() returns an object you destructure normally. Default values work with standard JS destructuring defaults. There is no propTypes, no separate TypeScript interface required (though you can add interface Props and annotate $props<Props>()).

React
function Button({ children, variant = 'primary', ...rest }) {
return (
<button className={'btn btn-' + variant} {...rest}>
{children}
</button>
);
}
Svelte
<script>
let { children, variant = 'primary', ...rest } = $props();
</script>
<button class="btn btn-{variant}" {...rest}>
{@render children?.()}
</button>

The ...rest spread forwards any extra attributes to the underlying element — exactly like React.

$bindable() — two-way props (no callback needed)

Section titled “$bindable() — two-way props (no callback needed)”

React requires “lifting state”: the parent owns the value, the child receives it as a prop and a setter callback. Svelte’s $bindable() lets the parent use bind:propName on the child, giving the child the ability to write back to the parent’s variable without any explicit callback.

React
// React: parent must own state + pass setter down
function TextInput({ value, onChange }) {
return <input value={value} onChange={e => onChange(e.target.value)} />;
}
function App() {
const [text, setText] = React.useState('');
return (
<div>
<TextInput value={text} onChange={setText} />
<p>You typed: {text}</p>
</div>
);
}
Svelte
<script>
// Child: TextInput.svelte
let { value = $bindable('') } = $props();
</script>
<input bind:value />
<!-- Parent usage: <TextInput bind:value={text} /> -->
How do you declare a prop with a default value in Svelte 5?
What does $bindable() allow that regular $props() does not?
How do you forward extra HTML attributes to the root element in a Svelte 5 component?