Learn SvelteKit - Reactive UI & Components
Episode 6 of 24

Learn SvelteKit - Reactive UI & Components

This episode covers the presentation side of SvelteKit: the basics of Svelte components with runes, reactive statements and bindings, slots and context modules for reusable components, and scoped styling with global CSS. You will build UI that is genuinely reactive to state changes.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Data already flows from the server to pages via load functions. Now we talk about how that data is displayed and how the UI responds to user interaction. Episode 6 is the heart of the Svelte experience: components, reactivity, and styling.

Svelte 5 introduced runes as the new way to write reactivity. The concept is more explicit than the old version and makes the mental model simpler: state declared with $state automatically triggers UI updates when it changes, with no virtual DOM.

After this episode, you can break an application into small reusable components, share data between components with slots and context, and control styling scope precisely.

Svelte Component Basics

Props with $props

Every Svelte component is a .svelte file containing script, markup, and style. Data coming in from the parent is declared with the $props rune.

Component with props
<script>
    let { nama, jumlah = 0 } = $props();
    let nilai = $state(0);
 
    function tambah() {
        nilai += 1;
    }
</script>
 
<h1>Halo, {nama}</h1>
<p>Nilai internal: {nilai}</p>
<p>Jumlah dari props: {jumlah}</p>
<button onclick={tambah}>Tambah</button>

The $props() rune defines the props the component accepts, complete with default values. This destructuring declaration makes the component API easy to read.

State with $state

The $state rune makes a variable reactive. Every time its value changes, the component re-renders automatically. No need to call a setter or special function — plain assignment is enough.

Svelte reactivity happens at the compiler level: code is transformed into precise updates. This differs from a virtual DOM that computes diffs at runtime, and it's what makes Svelte extremely light on the client.

Reactive Statements and Bindings

Derived with $derived

When a value is computed from other state and must always stay in sync, use $derived. Derived values are only recomputed when their dependencies change.

Derived and two-way binding
<script>
    let harga = $state(1000);
    let jumlah = $state(2);
    let total = $derived(harga * jumlah);
</script>
 
<input type="range" bind:value={harga} min="100" max="10000" step="100" />
<input type="number" bind:value={jumlah} min="1" />
 
<p>Total: Rp {total.toLocaleString("id-ID")}</p>

The bind:value directive creates a two-way binding: a change from the input writes to the state, and a change to the state writes to the input. Svelte provides many bindings: bind:value for inputs, bind:checked for checkboxes, bind:this for element references, and bind:group for radio groups.

Side Effects with $effect

To run code whenever state changes, for example saving a preference to localStorage, use $effect. Distinguish it from $derived: derived computes pure values, effect performs side actions. Use effects sparingly because they run whenever a dependency changes.

Slots and Context Modules

Children and Named Slots

Reusable components receive content from the parent through slots. In Svelte 5, content is carried as a children prop rendered with {@render children()}.

Card component with slots
<script>
    let { children, judul } = $props();
</script>
 
<article class="kartu">
    <h2>{judul}</h2>
    {@render children()}
</article>
 
<style>
    .kartu {
        border: 1px solid #e2e8f0;
        border-radius: 8px;
        padding: 1rem;
    }
</style>

With the children prop, components like cards, modals, or panels can be wrapped with arbitrary content. For named content, declare a prop with a string key and render it as needed.

Context Modules and setContext

A script module block runs once per application, not per component instance. It's suited for constants and helpers that don't depend on instance state.

To share data between components without passing it down layer after layer, use setContext and getContext from the svelte module. Context is bound to the component tree, so the same value is shared with all descendants but isolated per parent instance.

Scoped Styling and Global CSS

Scoped Styling

Styles inside a component's <style> are scoped: Svelte adds a unique class to elements and selectors. This prevents collisions between components and makes CSS easy to trace. Child selectors like .kartu p still work because the compiler adds the scope class to the relevant elements.

Global CSS and :global

To break out of the scope, use :global(...). This selector targets any element on the page without the scope class. Use it carefully and sparingly, for example for styles from an external library or resets that genuinely need to touch every element.

CSSGlobal CSS in a component
<style>
    :global(body) {
        font-family: "Inter", system-ui, sans-serif;
        margin: 0;
    }
 
    .kartu {
        background: var(--surface);
    }
</style>

CSS Variables

CSS variables --nama cross component boundaries and can be shared with a design system. Combine CSS variables with scoped styles to create a flexible theme without giving up scope control.

Closing

Key takeaways:

  • A Svelte component consists of script, markup, and style in a single .svelte file.
  • The $props rune for component inputs, $state for reactive state, $derived for derived values, and $effect for side effects.
  • Two-way binding with bind:value and its variants makes forms and interactions concise.
  • Slots (children) and named slots enable reusable components that accept arbitrary content.
  • setContext and getContext share data inside the component tree; script module for one-time code.
  • Svelte styling is scoped by default; :global() breaks out of the scope for special cases.

In the next episode we deepen state management: stores & state management. You'll learn writable, readable, and derived stores, custom stores for shared state, state synchronization between server and client, and integration with TanStack Query.

Learn SvelteKit - Reactive UI & Components | Learn SvelteKit