Discover why Svelte is gaining popularity and learn how to build efficient web applications with this innovative framework. 🚀
Understanding Svelte 🎯
Svelte is a radical new approach to building user interfaces. Unlike traditional frameworks that do most of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.
Project Setup
# Create new project
npm create vite@latest my-svelte-app -- --template svelte
cd my-svelte-app
npm install
Basic Component Structure
<!-- src/lib/Counter.svelte -->
<script>
let count = 0;
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Clicks: {count}
</button>
<style>
button {
padding: 0.5rem 1rem;
background: #ff3e00;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
Reactive Declarations 🔄
<script>
let count = 0;
$: doubled = count * 2;
$: if (count >= 10) {
alert('Count is getting high!');
}
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Count: {count}
</button>
<p>Doubled: {doubled}</p>
Props and Events 📡
<!-- Button.svelte -->
<script>
export let text = 'Click me';
export let color = 'primary';
</script>
<button
class={color}
on:click
>
{text}
</button>
<style>
button {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.primary {
background: #ff3e00;
color: white;
}
.secondary {
background: #676778;
color: white;
}
</style>
<!-- App.svelte -->
<script>
import Button from './Button.svelte';
function handleClick() {
alert('Button clicked!');
}
</script>
<Button
text="Click me!"
color="primary"
on:click={handleClick}
/>
Conditional Rendering 🔀
<script>
let user = null;
let loading = true;
async function fetchUser() {
const response = await fetch('/api/user');
user = await response.json();
loading = false;
}
</script>
{#if loading}
<p>Loading...</p>
{:else if user}
<h1>Welcome, {user.name}!</h1>
{:else}
<p>Please log in</p>
{/if}
Loops and Iterations 🔁
<script>
let todos = [
{ id: 1, text: 'Learn Svelte', done: false },
{ id: 2, text: 'Build an app', done: false }
];
function toggleTodo(id) {
todos = todos.map(todo =>
todo.id === id
? { ...todo, done: !todo.done }
: todo
);
}
</script>
<ul>
{#each todos as todo (todo.id)}
<li class:done={todo.done}>
<input
type="checkbox"
checked={todo.done}
on:change={() => toggleTodo(todo.id)}
/>
{todo.text}
</li>
{/each}
</ul>
<style>
.done {
text-decoration: line-through;
opacity: 0.7;
}
</style>
Stores for State Management 📦
// src/stores/todos.js
import { writable } from 'svelte/store';
export const todos = writable([]);
export function addTodo(text) {
todos.update(items => [
...items,
{
id: Date.now(),
text,
done: false
}
]);
}
export function toggleTodo(id) {
todos.update(items =>
items.map(todo =>
todo.id === id
? { ...todo, done: !todo.done }
: todo
)
);
}
<!-- TodoList.svelte -->
<script>
import { todos, addTodo, toggleTodo } from '../stores/todos';
let newTodoText = '';
function handleSubmit() {
if (newTodoText.trim()) {
addTodo(newTodoText);
newTodoText = '';
}
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<input
bind:value={newTodoText}
placeholder="Add new todo"
/>
<button type="submit">Add</button>
</form>
<ul>
{#each $todos as todo (todo.id)}
<li>
<input
type="checkbox"
checked={todo.done}
on:change={() => toggleTodo(todo.id)}
/>
{todo.text}
</li>
{/each}
</ul>
Lifecycle Methods 🔄
<script>
import { onMount, onDestroy } from 'svelte';
let interval;
let seconds = 0;
onMount(() => {
interval = setInterval(() => {
seconds += 1;
}, 1000);
});
onDestroy(() => {
clearInterval(interval);
});
</script>
<p>Time elapsed: {seconds} seconds</p>
Animations and Transitions 🎨
<script>
import { fade, fly } from 'svelte/transition';
import { elasticOut } from 'svelte/easing';
let visible = true;
</script>
<button on:click={() => visible = !visible}>
Toggle
</button>
{#if visible}
<div
transition:fly={{
y: 200,
duration: 2000,
easing: elasticOut
}}
>
Animated content
</div>
{/if}
Form Handling 📝
<script>
let formData = {
name: '',
email: '',
message: ''
};
function handleSubmit() {
console.log('Form data:', formData);
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<div class="form-group">
<label for="name">Name</label>
<input
id="name"
bind:value={formData.name}
required
/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
id="email"
type="email"
bind:value={formData.email}
required
/>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea
id="message"
bind:value={formData.message}
required
></textarea>
</div>
<button type="submit">Send</button>
</form>
<style>
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
}
input,
textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
API Integration 🌐
<script>
import { onMount } from 'svelte';
let posts = [];
let loading = true;
let error = null;
async function fetchPosts() {
try {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts'
);
posts = await response.json();
} catch (err) {
error = err.message;
} finally {
loading = false;
}
}
onMount(fetchPosts);
</script>
{#if loading}
<p>Loading posts...</p>
{:else if error}
<p class="error">Error: {error}</p>
{:else}
<div class="posts">
{#each posts as post}
<div class="post">
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
{/each}
</div>
{/if}
Best Practices 📝
- Keep components small and focused
- Use TypeScript for better type safety
- Implement proper error handling
- Use stores for global state
- Follow Svelte's reactivity rules
- Optimize performance
- Write maintainable code
- Use proper event handling
- Implement proper testing
- Follow accessibility guidelines
Additional Resources
Svelte offers a unique and powerful approach to building web applications. Its compile-time approach results in highly efficient applications with excellent performance characteristics. As you continue learning, explore more advanced features and best practices to build even better applications.