Beyond Static Markup
So far, BookIt displays the same content every time. But real applications need dynamic behavior. Show a login form or a dashboard depending on auth state. Display a list of services, not just one. Show loading spinners while data fetches. This is where control flow comes in.
What You’ll Learn
- What control flow means in Svelte’s template syntax
- The different block types Svelte provides
- When to use each type of block
- How control flow differs from JavaScript
What is Control Flow?
In JavaScript, you use if, else, and for to control program execution. In Svelte templates, you need something similar but for rendering. Svelte provides special block syntax that lets you conditionally render content and iterate over data directly in your markup.
Unlike JavaScript which executes once, Svelte’s template blocks are reactive. When the data they depend on changes, the rendered output updates automatically.
Svelte’s Control Flow Blocks
Svelte provides four main template blocks for control flow:
| Block | Purpose | Example Use Case |
|---|---|---|
{#if} | Conditional rendering | Show login form or dashboard |
{#each} | List iteration | Render all services |
{#await} | Async data handling | Show loading → data → error |
{#key} | Force re-creation | Reset component when ID changes |
In this module, we’ll focus on {#if} and {#each} — the two you’ll use most often. You’ll encounter {#await} in Module 9 when loading server data, and {#key} in advanced scenarios.
The Block Syntax Pattern
All Svelte blocks follow the same pattern:
{#blockname expression}
content
{/blockname} The # starts a block, / ends it. Some blocks have continuation tags using : for branches like {:else}.
Here’s a quick preview of what you’ll learn:
<!-- Conditional: show one thing or another -->
{#if isLoggedIn}
<Dashboard />
{:else}
<LoginForm />
{/if}
<!-- Iteration: render many items -->
{#each services as service}
<ServiceCard {service} />
{/each} Why Not Just Use JavaScript?
You might wonder why Svelte needs special syntax. Why not just use JavaScript?
<!-- This doesn't work in Svelte templates -->
<div>
{ if (isLoggedIn) { return <Dashboard /> } }
</div> Svelte templates aren’t JavaScript — they’re a declarative description of your UI. The block syntax provides a clean, readable way to express conditional and iterative rendering while maintaining reactivity.
Compare the readability:
<!-- Svelte's approach: clear and declarative -->
{#if user}
<p>Welcome, {user.name}!</p>
{:else}
<p>Please log in.</p>
{/if}
<!-- Ternary alternative: gets messy fast -->
{user ? `<p>Welcome, ${user.name}!</p>` : '<p>Please log in.</p>'} For simple cases, you can use ternary expressions in Svelte. But as conditions grow complex, block syntax stays readable.
Control Flow in BookIt
Throughout this module, you’ll build these BookIt features using control flow:
Conditional rendering:
- Show booking form or confirmation based on submission state
- Display different content per category
- Handle loading and error states
List iteration:
- Render all services from an array
- Display booking history
- Show category filter buttons
Combined patterns:
- Filter services by category (condition + iteration)
- Show “no results” when filters match nothing (condition inside iteration)
How This Module Progresses
Here’s what’s ahead:
- Conditional Rendering —
{#if},{:else}, and{:else if}for showing/hiding content - Empty States — Handle the “nothing to show” case gracefully
- Each Blocks — Render lists of items with
{#each} - Keyed Each — Why unique identifiers matter for dynamic lists
- Filter Services — Combine everything into an interactive filtered display
By the end, BookIt’s services page will display a categorized, filterable list with proper empty states — all built with Svelte’s control flow primitives.
A Quick Taste
Here’s a glimpse of what you’ll build by the end of this module:
<script>
let selectedCategory = $state('all');
const services = [
{ id: '1', name: 'Lawn Mowing', category: 'lawn-care', price: 50 },
{ id: '2', name: 'Tree Pruning', category: 'tree-care', price: 150 },
// ... more services
];
let filteredServices = $derived(
selectedCategory === 'all'
? services
: services.filter(s => s.category === selectedCategory)
);
</script>
<!-- Category filter buttons -->
{#each categories as category}
<button onclick={() => selectedCategory = category.id}>
{category.name}
</button>
{/each}
<!-- Filtered service list with empty state -->
{#if filteredServices.length > 0}
{#each filteredServices as service (service.id)}
<ServiceCard {service} />
{/each}
{:else}
<p>No services found in this category.</p>
{/if} Conditions, loops, and derived state work together to create a dynamic, reactive interface.
Summary
Svelte’s control flow blocks let you conditionally render content and iterate over data directly in templates. The syntax is declarative, readable, and fully reactive — when data changes, the UI updates automatically.
Key takeaways:
{#if}handles conditional rendering{#each}handles list iteration- Block syntax uses
#to start,/to end, and:for branches - Control flow blocks are reactive by default
Next Steps
Let’s start with the most common pattern. Continue with Conditional Rendering to learn {#if}, {:else}, and {:else if} for showing and hiding content.