Lesson 7 / 25

$props

Typed inputs with defaults.

Destructuring props

A component reads its inputs with let { title, count = 0, ...rest } = $props(). Defaults apply when the parent passes undefined; the rest pattern collects remaining attributes, which you can spread onto an element with {...rest}. Props update when the parent changes them. With TypeScript, describe them with an interface and annotate the destructuring: let { title }: Props = $props(). You can extend element attribute types such as HTMLButtonAttributes from svelte/elements. Treat props as read-only unless they are bindable. Svelte 4 used export let title; and $$restProps.

Data down, callbacks and snippets in

Components receive props, report changes through callbacks or bindings, and accept markup as snippets.

Three ideas: $props, events and $bindable, snippets and {@render}.
Figure 3.1 — Parent passes props and snippets; child calls back or binds.

A typed Button component

Defaults, rest props and spread.

<!-- Button.svelte -->
<script lang="ts">
  import type { HTMLButtonAttributes } from 'svelte/elements';

  interface Props extends HTMLButtonAttributes {
    variant?: 'primary' | 'ghost';
    label: string;
  }

  let { variant = 'primary', label, ...rest }: Props = $props();
</script>

<button class={variant} {...rest}>{label}</button>

<!-- Usage in a parent:
<Button label="Save" type="submit" />
<Button label="Cancel" variant="ghost" onclick={close} />
-->

Use $props.id for accessible ids

Svelte 5 provides $props.id() to generate an id unique to the component instance and stable between server and client, useful for label and aria attributes. Check the docs for your version.

Quick check: How does a Svelte 5 component declare a prop with a default value?

  • let { size = 16 } = $props();
  • export let size = 16;
  • const size = $state.prop(16);
  • props.size ||= 16;
Answer

let { size = 16 } = $props(); — Svelte 4 used export let; Svelte 5 uses $props.