Imagine opening an app and always seeing the same thing, no matter who you are or what you’ve done.
- You’re logged out? Still says “Welcome back!”.
- You’re logged in? Still says “Please log in.”.
- You’re waiting for something to load? The app just… stares blankly at you.
Not great, right?
This is why we need conditional rendering: the ability to show (or hide) parts of the UI depending on what’s going on. Think of it like stage lighting 🎭: only the actors relevant to the current scene get the spotlight.
In this article we’ll explore:
- How to show something only if a condition is true.
- How to add an else branch.
- How to handle multiple cases with
else if
. - How to nest conditions carefully.
- Common gotchas you might trip on.
And, as always: no prior knowledge assumed. Every example will be fully explained, copy-paste ready, with file paths included.
Step 1: The {#if}
Block
The simplest conditional is just an “if this is true, then show this.”
📂 src/lib/Welcome.svelte
<script>
let loggedIn = $state(false);
</script>
{#if loggedIn}
<h1>Welcome back!</h1>
{/if}
<button on:click={() => (loggedIn = !loggedIn)}>
{loggedIn ? 'Logout' : 'Login'}
</button>
📂 src/routes/+page.svelte
<script>
import Welcome from '$lib/Welcome.svelte';
</script>
<Welcome />
Breaking it down 🪄
let loggedIn = $state(false);
This is our little “switch.” Starts atfalse
, meaning “user not logged in.” Because it’s$state
, the UI will update whenever it changes.{#if loggedIn} ... {/if}
Only runs the inside code if the condition is true. IfloggedIn
is false, it renders nothing at all.The
<button>
FlipsloggedIn
between true and false. We even change the button label with a ternary (loggedIn ? 'Logout' : 'Login'
).
👉 Try it: load the page, click the button. The <h1>
pops in and out of existence! You’ve just made your UI dynamic.
Analogy time: it’s like a light switch 💡. If loggedIn
is on (true), the lamp shows. If it’s off (false), the lamp vanishes.
Step 2: Adding {:else}
Okay, but right now, when you’re logged out, the screen goes blank. That’s like a party host who only greets people they know — otherwise they just… stare at you. Awkward.
We can fix that with {:else}
:
📂 src/lib/Welcome.svelte
<script>
let loggedIn = $state(false);
</script>
{#if loggedIn}
<h1>Welcome back!</h1>
{:else}
<h1>Please log in</h1>
{/if}
<button on:click={() => (loggedIn = !loggedIn)}>
{loggedIn ? 'Logout' : 'Login'}
</button>
📂 src/routes/+page.svelte
<script>
import Welcome from '$lib/Welcome.svelte';
</script>
<Welcome />
Breaking it down 🧩
Two branches, one outcome.
IfloggedIn
is true → show “Welcome back!”.
If not → show “Please log in”.UI is never empty.
Someone always has the spotlight — either the logged-in actor or the logged-out one.
Analogy: It’s like a friendly doorman 🚪. If they recognize you, they say “Welcome back!”. If they don’t, they politely say “Please log in.”. There’s always a response.
👉 Try it: toggle the button and watch the messages swap back and forth.
Step 3: {:else if}
for Multiple Cases
Life isn’t always binary. Sometimes we need three or more states.
Example:
- While data is loading → show “Loading…”
- Once loaded and user is authenticated → show “Welcome back!”
- Otherwise → show “Please log in.”
📂 src/lib/AuthStatus.svelte
<script>
let status = $state('loggedOut');
function setLoading() {
status = 'loading';
setTimeout(() => {
status = 'loggedOut';
}, 2000);
}
function login() { status = 'loggedIn'; }
function logout() { status = 'loggedOut'; }
</script>
{#if status === 'loading'}
<p>Loading…</p>
{:else if status === 'loggedIn'}
<p>Welcome back!</p>
{:else}
<p>Please log in.</p>
{/if}
<div style="margin-top: 1rem;">
<button on:click={setLoading}>Set Loading</button>
<button on:click={login}>Login</button>
<button on:click={logout}>Logout</button>
</div>
📂 src/routes/+page.svelte
<script>
import AuthStatus from '$lib/AuthStatus.svelte';
</script>
<AuthStatus />
Breaking it down 🎛️
status = $state('loading')
Our variable can hold"loading"
,"loggedIn"
, or"loggedOut"
.-
{#if …} {:else if …} {:else}
Works just like a traffic light 🚦:- If red (
loading
), show “Loading…” - If green (
loggedIn
), show “Welcome back!” - Otherwise (yellow =
loggedOut
), show “Please log in.”
- If red (
Buttons let us simulate flipping between states. Notice how the UI updates instantly with each change.
👉 Try it yourself:
- Click “Set Loading.” You’ll see “Loading…” for 2 seconds, then it flips to “Please log in.”
- Click “Login.” UI now says “Welcome back!”
- Click “Logout.” UI says “Please log in.”
You’ve just seen conditional rendering handle multiple possibilities like a champ.
Step 4: Nesting Conditionals (with Care)
Sometimes conditions depend on two things at once. For example:
- Is the user logged in?
- And if yes, are they an admin?
📂 src/lib/UserStatus.svelte
<script>
let loggedIn = $state(false);
let isAdmin = $state(false);
function loginAsUser() { loggedIn = true; isAdmin = false; }
function loginAsAdmin() { loggedIn = true; isAdmin = true; }
function logout() { loggedIn = false; isAdmin = false; }
</script>
{#if loggedIn}
{#if isAdmin}
<p>Welcome, mighty admin!</p>
{:else}
<p>Welcome, regular user.</p>
{/if}
{:else}
<p>Please log in.</p>
{/if}
<div style="margin-top: 1rem;">
<button on:click={loginAsUser}>Login as User</button>
<button on:click={loginAsAdmin}>Login as Admin</button>
<button on:click={logout}>Logout</button>
</div>
📂 src/routes/+page.svelte
<script>
import UserStatus from '$lib/UserStatus.svelte';
</script>
<UserStatus />
Breaking it down 🧩
- We track two pieces of state:
loggedIn
andisAdmin
. - If not logged in → show “Please log in.”
- If logged in and admin → show “Welcome, mighty admin!”
- If logged in but not admin → show “Welcome, regular user.”
👉 Analogy: It’s like a club entrance 🚪. First the bouncer checks if you’re on the guest list (logged in). If yes, they check your VIP pass (admin). Depending on both, you get different treatment.
⚠️ Warning: Nesting {#if}
blocks inside each other can get messy fast. If you find yourself stacking three or four deep, it may be time to restructure your code (e.g. combine conditions into a single variable, or split logic into smaller components).
Step 5: Common Gotchas
Conditionals are simple on the surface, but beginners often trip over the same issues. Let’s clear them up.
1) Truthy and Falsy Values
📂 src/lib/CounterCheck.svelte
<script>
let count = $state(0);
</script>
{#if count}
<p>Count is nonzero: {count}</p>
{:else}
<p>Count is zero</p>
{/if}
<button on:click={() => count++}>Increment</button>
👉 Remember: in JavaScript, 0
is falsy. So {#if count}
won’t show until count
becomes 1 or more.
It’s like asking “Do we have cookies?” If the jar is empty (0
), the answer is no. Only once there’s at least one cookie does the conditional pass. 🍪
2) Automatic Reactivity
📂 src/lib/ToggleExample.svelte
<script>
let visible = $state(false);
</script>
{#if visible}
<p>You can see me now!</p>
{:else}
<p>Now I’m hidden.</p>
{/if}
<button on:click={() => (visible = !visible)}>
Toggle
</button>
👉 You don’t need to “force” a re-render.
When visible
changes, Svelte automatically re-evaluates the {#if}
and updates the DOM.
Think of it like a thermostat 🌡️. You don’t tell the heater “re-render the room!”. You just change the temperature setting, and the system adjusts itself.
3) Performance
Worried about performance? Don’t be (at least not yet). Svelte compiles these {#if}
blocks into super efficient code. Unless you’re toggling thousands of elements every frame, you’re fine.
Step 6: Quick Recap
We’ve covered a lot of ground! Let’s review:
-
{#if}
→ show something only when a condition is true. -
{:else}
→ provide a fallback when the condition is false. -
{:else if}
→ handle multiple possibilities in sequence. - Nesting → possible, but keep it tidy.
- Gotchas → remember truthy/falsy rules and trust Svelte’s reactivity.
👉 Big picture: conditional rendering makes your UI context-aware. Your app can respond to state changes and show the right thing at the right time.
What’s Next?
We’ve now taught our app how to make decisions. But sometimes we don’t want to choose one thing — we want to render a list of things.
For that, we’ll need loops. And that’s exactly what we’ll tackle in the next article. 🚀
Next article: Loops in Svelte — {#each}, Keys, and Building a Todo App
Follow me on DEV for future posts in this deep-dive series.
https://dev.to/a1guy
If it helped, leave a reaction (heart / bookmark) — it keeps me motivated to create more content
Checkout my offering on YouTube with (growing) crash courses and content on JavaScript, React, TypeScript, Rust, WebAssembly, AI Prompt Engineering and more: @LearnAwesome
Top comments (0)