🎭 Svelte’s Shape-Shifters: Dynamic Rendering Magic
Imagine a magical toy box where toys can transform into ANY other toy you want, just by thinking about it!
🌟 The Big Idea
In Svelte, sometimes you don’t know WHAT component or element you need until your app is running. That’s where Dynamic Rendering comes in—special elements that can become anything you need!
Think of it like a chameleon 🦎 that changes color based on its surroundings. These special elements change what they ARE based on your data!
🧩 Meet the Three Shape-Shifters
| Element | Superpower | When to Use |
|---|---|---|
<svelte:component> |
Becomes ANY component | Switching between components |
<svelte:element> |
Becomes ANY HTML tag | Dynamic tag names |
<svelte:self> |
Becomes ITSELF again | Recursive structures |
🎪 <svelte:component> — The Component Chameleon
What is it?
It’s a placeholder that says: “I’ll become whatever component you tell me to be!”
Real-Life Example
Imagine a remote control with buttons for TV, Radio, and Game Console. Each button shows a DIFFERENT screen—but you only have ONE screen area!
<script>
import TV from './TV.svelte';
import Radio from './Radio.svelte';
import Game from './Game.svelte';
let screens = { tv: TV, radio: Radio, game: Game };
let current = 'tv';
</script>
<svelte:component this={screens[current]} />
<button on:click={() => current = 'tv'}>📺 TV</button>
<button on:click={() => current = 'radio'}>📻 Radio</button>
<button on:click={() => current = 'game'}>🎮 Game</button>
How It Works
graph TD A["User clicks button"] --> B{Which button?} B -->|TV| C["screens.tv = TV component"] B -->|Radio| D["screens.radio = Radio component"] B -->|Game| E["screens.game = Game component"] C --> F["svelte:component shows TV"] D --> F["svelte:component shows Radio"] E --> F["svelte:component shows Game"]
Key Points
✅ Use this={ComponentName} to specify which component
✅ If this is null or undefined, nothing renders
✅ You can pass props just like normal components!
<svelte:component
this={currentComponent}
name="Alex"
age={10}
/>
🏷️ <svelte:element> — The Tag Transformer
What is it?
Instead of changing COMPONENTS, this one changes the HTML tag itself!
Real-Life Example
Think of a heading that could be big (h1), medium (h2), or small (h3) depending on importance—like adjusting your voice volume!
<script>
let importance = 'h1';
</script>
<svelte:element this={importance}>
I'm a dynamic heading!
</svelte:element>
<select bind:value={importance}>
<option value="h1">Big (h1)</option>
<option value="h2">Medium (h2)</option>
<option value="h3">Small (h3)</option>
</select>
Another Example: Dynamic List Type
<script>
let listType = 'ul';
</script>
<svelte:element this={listType}>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</svelte:element>
<button on:click={() => listType = 'ul'}>
Bullets •
</button>
<button on:click={() => listType = 'ol'}>
Numbers 1.
</button>
Visual Flow
graph TD A["listType = &#39;ul&#39;"] --> B["svelte:element this=&#39;ul&#39;"] B --> C["Renders as bullet list"] D["listType = &#39;ol&#39;"] --> E["svelte:element this=&#39;ol&#39;"] E --> F["Renders as numbered list"]
Key Points
✅ Works with ANY valid HTML tag name
✅ If this is falsy, nothing renders
✅ Add attributes normally!
<svelte:element
this={tag}
class="styled"
id="my-element"
>
Content here
</svelte:element>
🪞 <svelte:self> — The Mirror Magic
What is it?
A component that can include itself! It’s like standing between two mirrors and seeing infinite reflections 🪞🪞🪞
When Do You Need This?
When you have nested data that looks the same at every level:
- Folder with folders inside 📁
- Comments with replies that have replies
- Family tree (parent → child → grandchild)
Real-Life Example: Folder Tree
<!-- Folder.svelte -->
<script>
export let folder;
</script>
<div class="folder">
📁 {folder.name}
{#if folder.children}
<div class="indent">
{#each folder.children as child}
<svelte:self folder={child} />
{/each}
</div>
{/if}
</div>
<style>
.indent { margin-left: 20px; }
</style>
Using It
<script>
import Folder from './Folder.svelte';
let files = {
name: 'Documents',
children: [
{ name: 'Photos', children: [
{ name: 'Vacation' },
{ name: 'Birthday' }
]},
{ name: 'Music' }
]
};
</script>
<Folder folder={files} />
What It Renders
📁 Documents
📁 Photos
📁 Vacation
📁 Birthday
📁 Music
Visual Explanation
graph TD A["Folder: Documents"] --> B["svelte:self"] B --> C["Folder: Photos"] C --> D["svelte:self"] D --> E["Folder: Vacation"] D --> F["Folder: Birthday"] B --> G["Folder: Music"]
Key Points
✅ Only works INSIDE the component that uses it
✅ Must have a stopping condition (like {#if folder.children})
✅ Without a stop, you get infinite loops! 💥
🎯 When to Use Each?
| Situation | Use This |
|---|---|
| “Show component A or B based on user choice” | <svelte:component> |
| “Render as div, span, or button based on prop” | <svelte:element> |
| “Display nested tree-like data” | <svelte:self> |
🚀 Pro Tips
Tip 1: Combining with Stores
<script>
import { currentView } from './stores.js';
import Home from './Home.svelte';
import Settings from './Settings.svelte';
const views = { home: Home, settings: Settings };
</script>
<svelte:component this={views[$currentView]} />
Tip 2: Fallback When Empty
{#if componentToShow}
<svelte:component this={componentToShow} />
{:else}
<p>Nothing to display!</p>
{/if}
Tip 3: Events Work Too!
<svelte:component
this={Button}
on:click={handleClick}
/>
<svelte:element
this="button"
on:click={handleClick}
>
Click me!
</svelte:element>
🎉 Summary
You just learned Svelte’s THREE dynamic rendering superpowers:
<svelte:component>— Swap entire components like changing TV channels 📺<svelte:element>— Change HTML tags like adjusting volume 🔊<svelte:self>— Create recursive structures like mirror reflections 🪞
These tools let you build flexible, dynamic UIs that adapt to ANY situation. You’re now a dynamic rendering wizard! 🧙♂️✨
🧪 Try It Yourself!
Create a simple “Tab Switcher” that uses <svelte:component> to show different content panels. Then try building a comment system with nested replies using <svelte:self>!
Happy coding! 🎈
