Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sveltejs/svelte/llms.txt

Use this file to discover all available pages before exploring further.

Props and state are the fundamental ways to manage data in Svelte components. Props pass data from parent to child, while state manages data within a component.

Component Props

Props (short for properties) are how you pass data to components. You pass props just like you pass attributes to elements:
<!-- App.svelte -->
<script>
  import MyComponent from './MyComponent.svelte';
</script>

<MyComponent adjective="cool" count={42} />

Declaring Props with $props

Inside the child component, receive props with the $props rune:
<!-- MyComponent.svelte -->
<script>
  let props = $props();
</script>

<p>This component is {props.adjective}</p>
<p>Count: {props.count}</p>
1
Destructuring Props
2
More commonly, you’ll destructure your props:
3
<script>
  let { adjective, count } = $props();
</script>

<p>This component is {adjective}</p>
<p>Count: {count}</p>
4
Fallback Values
5
Provide default values for props that may not be passed:
6
<script>
  let { adjective = 'happy', count = 0 } = $props();
</script>
7
Renaming Props
8
Use destructuring assignment to rename props:
9
<script>
  let { class: className, super: trouper = 'lights are gonna find me' } = $props();
</script>
10
Rest Props
11
Capture remaining props with a rest property:
12
<script>
  let { title, description, ...others } = $props();
</script>

<div {...others}>
  <h1>{title}</h1>
  <p>{description}</p>
</div>

Type-Safe Props

Add type safety using TypeScript:
<script lang="ts">
  interface Props {
    name: string;
    age: number;
    email?: string;
  }
  
  let { name, age, email = 'N/A' }: Props = $props();
</script>

<div>
  <p>Name: {name}</p>
  <p>Age: {age}</p>
  <p>Email: {email}</p>
</div>
Or using JSDoc:
<script>
  /** @type {{ name: string, age: number }} */
  let { name, age } = $props();
</script>

Component State

The $state rune creates reactive state within a component:
<script>
  let count = $state(0);
</script>

<button onclick={() => count++}>
  clicks: {count}
</button>

Deep Reactive State

Arrays and objects become deeply reactive state proxies:
<script>
  let todos = $state([
    { done: false, text: 'add more todos' }
  ]);
  
  function addTodo() {
    todos.push({ done: false, text: 'new todo' });
  }
  
  function toggleTodo(index) {
    todos[index].done = !todos[index].done;
  }
</script>

<ul>
  {#each todos as todo, i}
    <li>
      <input type="checkbox" bind:checked={todo.done} />
      {todo.text}
    </li>
  {/each}
</ul>

<button onclick={addTodo}>Add Todo</button>

State in Classes

Use $state in class fields:
<script>
  class Todo {
    done = $state(false);
    
    constructor(text) {
      this.text = $state(text);
    }
    
    reset = () => {
      this.text = '';
      this.done = false;
    }
  }
  
  let todo = new Todo('Learn Svelte');
</script>

<div>
  <input type="checkbox" bind:checked={todo.done} />
  <input bind:value={todo.text} />
  <button onclick={todo.reset}>Reset</button>
</div>

Derived State

Create computed values with the $derived rune:
<script>
  let count = $state(0);
  let doubled = $derived(count * 2);
  let quadrupled = $derived(doubled * 2);
</script>

<button onclick={() => count++}>Increment</button>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<p>Quadrupled: {quadrupled}</p>
For complex derivations, use $derived.by:
<script>
  let items = $state([1, 2, 3, 4, 5]);
  
  let stats = $derived.by(() => {
    const sum = items.reduce((a, b) => a + b, 0);
    const average = sum / items.length;
    return { sum, average, count: items.length };
  });
</script>

<p>Sum: {stats.sum}</p>
<p>Average: {stats.average}</p>
<p>Count: {stats.count}</p>

Bindable Props

Create two-way bindings with $bindable:
<!-- FancyInput.svelte -->
<script>
  let { value = $bindable(), ...props } = $props();
</script>

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

<style>
  input {
    font-family: 'Comic Sans MS';
    color: deeppink;
  }
</style>
<!-- App.svelte -->
<script>
  import FancyInput from './FancyInput.svelte';
  
  let message = $state('hello');
</script>

<FancyInput bind:value={message} />
<p>{message}</p>

Updating Props

References to props update automatically when the prop changes. You can temporarily reassign props:
<!-- Child.svelte -->
<script>
  let { count } = $props();
</script>

<button onclick={() => count += 1}>
  clicks (child): {count}
</button>
However, avoid mutating props unless they are bindable. Use callback props or $bindable for parent-child communication.

Unique IDs with $props.id()

Generate unique IDs for component instances:
<script>
  const uid = $props.id();
</script>

<form>
  <label for="{uid}-firstname">First Name:</label>
  <input id="{uid}-firstname" type="text" />
  
  <label for="{uid}-lastname">Last Name:</label>
  <input id="{uid}-lastname" type="text" />
</form>

Raw State

For non-reactive objects, use $state.raw:
<script>
  let person = $state.raw({
    name: 'Heraclitus',
    age: 49
  });
  
  // Only reassignment works, not mutation
  function birthday() {
    person = { ...person, age: person.age + 1 };
  }
</script>

State Snapshots

Take static snapshots of reactive state:
<script>
  let counter = $state({ count: 0 });
  
  function logSnapshot() {
    console.log($state.snapshot(counter));
  }
</script>

<button onclick={() => counter.count++}>Increment</button>
<button onclick={logSnapshot}>Log Snapshot</button>