So, I've been playing around with Svelte, this unique JavaScript compiler, for a while now, and let me tell you, it's awesome! As someone who's experienced with React, using Svelte feels like a refreshing change of pace. I'm not here to pit React against Svelte - plenty of articles already do that. Instead, I want to share some cool stuff I've learned while using Svelte.
Svelte Spring
Svelte comes with a built-in spring animation library that's super easy to use and lightning-fast! You just specify the spring parameters and boom! The animation takes care of itself. Check out this example:
<script>
import { spring } from "svelte/motion";
let x = spring(0, {
stiffness: 0.1,
damping: 0.1,
});
</script>
<svelte:body on:mousemove={({ clientX }) => (x = clientX)} />
<div style="transform: translateX({$x}px)"></div>
And voila! You get a nice springy animation! It's that simple.
Learn more: Svelte Tutorial - Tweened, Svelte Tutorial - Spring
Svelte Transitions
But wait, there's more! Svelte not only has spring animations, but it also comes with a transition library. Adding a transition is a piece of cake - just slap the transition
attribute on an element.
<script>
import { slide } from "svelte/transition";
let show = true;
</script>
<label>
<input type="checkbox" bind:checked="{show}" />
slide
</label>
{#if show}
<h1 transition:slide>Hey🫡👀</h1>
{/if}
You've got a sliding effect like magic!
Svelte also has something called Deferred Transitions, which only run when an element is added or removed from the DOM. Check out this icon morphing to a div example:
The best part? It's less than 90 lines of code!
<script>
import { quintInOut } from "svelte/easing";
import { crossfade } from "svelte/transition";
let openApp = "";
let apps = ["🐦","🐱","🐶","🐭","🐹","🐰","🦊","🐻","🐼","🐨","🐯","🦁","🐮","🐷","🐸","🐵","🐔","🐧","🐤",];
const [send, receive] = crossfade({
duration: 500,
easing: quintInOut,
});
</script>
{#each apps as app}
{#if openApp !== app}
<button
class="icon"
on:click={() => (openApp = app)}
in:receive|global={{ key: app }}
out:send|global={{ key: app }}
>
{app}
</button>
{:else}
<div
class="app"
in:receive|global={{ key: app }}
out:send|global={{ key: app }}
>
<h1>App {app}</h1>
<button on:click={() => (openApp = "")}>Close</button>
</div>
{/if}
{/each}
Learn more: Svelte Tutorial - Transition, Svelte Deferred Transitions
Keyed Each Blocks
When it comes to lists in Svelte, you use the each
block. Svelte handles the key for you by default, but if you want more control, you can specify a key yourself.
<script>
let items = [
{ id: 1, name: "Joe" },
{ id: 2, name: "John" },
{ id: 3, name: "Jane" },
// ...
];
</script>
{#each items as item (item.id)}
<div>
<h1>{item.name}</h1>
</div>
{/each}
Just add (item.id)
after the each
block to specify the key.
Awaited Blocks
Here's a nifty feature: using awaited
blocks when you want to wait for a promise to resolve before rendering something.
Take this example using the fetch
API to get a random number from a server:
<script>
let promise = getRandomNumber();
async function getRandomNumber() {
const res = await fetch(`/tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>Generate Random Number</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
Sending Messages Between Components
Picture this: you've got a component rendering a list of items, and each item has a button that deletes it. You want
to update the list when an item is deleted, but how do you do that?
With Svelte's createEventDispatcher
function, you can send a message from the child component to the parent component.
In the child component, create a dispatcher and dispatch a message when the button is clicked:
<script>
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
function sendMsg() {
dispatch("refresh");
}
export let item = "";
</script>
<button on:click={sendMsg}>
Send Message
{item}
</button>
In the parent component, listen for the message and update the list:
<script>
import { onMount } from "svelte";
import Inner from "./Inner.svelte";
let items = [];
function handleRefresh() {
items = [...items, Math.random().
toString(36).split("").slice(2, 15)];
}
onMount(() => {
handleRefresh();
});
</script>
{#each items as item}
<Inner on:refresh={handleRefresh} {item} />
<br>
{/each}
Named Slots
In Svelte, when you're working with slots, you have the option to name them, which comes in handy when you want to pass multiple slots to a component.
Let's say we have a card component like this:
<div>
<h1>
<slot name="title" />
</h1>
<div>
<slot name="content" />
</div>
<slot name="footer">
<p>I'm the default footer. I'll be used if no other footer is provided.</p>
</slot>
<div>
<button>Interesting</button>
</div>
</div>
We can use our card component like this:
<Card>
<h1 slot="title">Default title</h1>
<p slot="content">Default content</p>
</Card>
By adding a slot
attribute to the element we want to pass to the slot and setting the value to the name of the slot, we can achieve this. It allows us to customize different parts of the card easily.
Named Exports
By default, Svelte exports a component as the default export. However, if you need additional exports, you can use named exports.
In your component file:
<script context="module">
export const name = "Svelte";
</script>
<script>
let test = "test";
</script>
By adding the context="module"
attribute to the first script tag, Svelte recognizes it as a module script.
You can then import the named export like this:
<script>
import { name } from "./Component.svelte";
</script>
This allows you to have multiple exports from a single component.
@const
and @html
Tags
While less known, the @const
and @html
tags can be useful in certain situations.
@const
Inside an {#if}
or {#each}
block, you can use the @const
tag to create a constant variable within the block.
{#each items as item}
{@const index = item.index}
<!-- Some code -->
<p>{index}</p>
<!-- Some code -->
<pre>I'm index {index}</pre>
{/each}
This saves time by avoiding repetitive code and duplications.
@html
The @html
tag allows you to render HTML inside a component. Unlike React's dangerouslySetInnerHTML
, Svelte's @html
is straightforward to use. However, be cautious when using it, as it can lead to XSS attacks.
<script>
let html = "<h1>HTML</h1>";
</script>
{@html html}
It provides a way to insert dynamic HTML content into your component, but be sure to sanitize any user-generated content before using it to prevent security issues.
Conclusion
In conclusion, Svelte has proven to be a fantastic JavaScript compiler with its intuitive features like spring animations, transitions, named slots, and more. It offers a refreshing alternative to other frameworks. So, give it a try and start building amazing web applications with Svelte today!
For more tech insights and updates, don't forget to follow me on Twitter and GitHub! Find me @posandu. Happy coding! 🚀
Svelte, JavaScript compiler, React, Svelte Spring, Svelte Transitions, Deferred Transitions, Keyed Each Blocks, Awaited Blocks, Sending Messages Between Components, Named Slots, Named Exports, @const, @html, web development, front-end development, web frameworks, animation library, web applications, JavaScript frameworks, programming, coding, developer, tech insights, GitHub, Twitter, coding tips, Svelte tutorial, Svelte examples, Svelte features, Svelte components.
Here's some stuff I learned after working with Svelte 👇https://t.co/gGPnMOVJaP
— Posandu - posandu.sol (@posandu) July 22, 2023
Top comments (2)
This Insights are Epic
Thank you!