Claude vs Gemini vs Grok: Svelte
Svelte 5 Tutorial
Svelte 5 introduces significant changes with the new runes system. Here's a comprehensive tutorial to get you started.
Table of Contents
- What's New in Svelte 5
- Installation
- Basic Concepts
- Runes System
- Components
- Event Handling
- Conditional Rendering
- Lists and Loops
- Stores
- Example Project
What's New in Svelte 5 {#whats-new}
- Runes: New reactive system replacing
let
,$:
, and stores - Better TypeScript support
- Improved performance
- Simplified mental model
- Enhanced developer experience
Installation {#installation}
# Create a new Svelte 5 project
npm create svelte@latest my-app
cd my-app
npm install
npm run dev
Basic Concepts {#basic-concepts}
Simple Component
<!-- App.svelte -->
<script>
import { state } from 'svelte/reactivity';
let name = state('World');
</script><h1>Hello {name.value}!</h1>
<input bind:value={name.value} />
Runes System {#runes-system}
Runes are the new reactive primitives in Svelte 5.
$state
Creates reactive state:
<script>
let count = $state(0);
let user = $state({
name: 'John',
age: 30
});
</script><button onclick={() => count++}>
Count: {count}
</button>
<p>User: {user.name}, Age: {user.age}</p>
<button onclick={() => user.age++}>
Increase Age
</button>
$derived
Creates computed values:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
let message = $derived(`Count is ${count}`);
</script><p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<p>{message}</p>
<button onclick={() => count++}>Increment</button>
$effect
Handles side effects:
<script>
let count = $state(0);
$effect(() => {
console.log(`Count changed to: ${count}`);
// Cleanup function (optional)
return () => {
console.log('Cleaning up effect');
};
});
</script><button onclick={() => count++}>
Count: {count}
</button>
$props
Handles component properties:
<!-- Child.svelte -->
<script>
let { title, count = 0, onClick } = $props();
</script><div>
<h2>{title}</h2>
<p>Count: {count}</p>
<button {onclick}>Click me</button>
</div>
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let count = $state(0);
function handleClick() {
count++;
}
</script><Child
title="My Component"
{count}
onClick={handleClick}
/>
Components {#components}
Component Communication
```svelte
Svelte 5: A Comprehensive Tutorial (with examples)
Svelte 5, also known as the "Runes" release, brings a significant paradigm shift to Svelte development. It introduces a new way to manage state and reactivity, based on runes, which are special symbols that attach behaviors to variables. This tutorial covers the core concepts and practical applications of Svelte 5.
Why Runes?
Runes provide:
- Explicit reactivity: You explicitly mark variables that should be reactive, making code easier to understand and debug.
- Fine-grained control: You have more control over when and how updates happen.
- Improved performance: Svelte can optimize reactivity more effectively with explicit signals.
- Better tooling: The explicit nature of runes enables better IDE support and linting.
Prerequisites:
- Basic understanding of HTML, CSS, and JavaScript.
- Node.js and npm (or a similar package manager) installed.
Setup:
- Create a Svelte project:
npm create svelte@latest my-svelte-app
cd my-svelte-app
npm install
npm run dev
Choose the "skeleton project" option.
- Update Svelte and Vite:
npm install svelte@next vite@next
- Configure
svelte.config.js
:
Open
svelte.config.js
and ensure the kit
config includes compilerOptions: { runes: true }
. This enables rune support.
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter(),
// Override http methods in the Todo list example
methodOverride: {
allowed: ['PATCH', 'DELETE']
}
},
preprocess: [vitePreprocess()],
compilerOptions: {
runes: true
}
};
export default config;
Core Concepts: Runes
Svelte 5 introduces several runes. Here are the key ones:
$
(Dollar Sign): This is the most fundamental rune. It's used to create reactive variables. When the value of a reactive variable changes, Svelte automatically updates the parts of the component that depend on it.$derived
: Creates derived signals. Derived signals are automatically updated when their dependencies (other signals) change. Think of them as computed properties.$effect
: Runs a function whenever its dependencies change. Useful for side effects like logging, DOM manipulation, or fetching data.$state
: (Less frequently used directly in components, mainly for libraries) Declares a variable as stateful, allowing it to be passed to components usingbind:
orlet:
.$const
: Declares a variable whose value should not be changed after initialization. (Note: While it prevents reassignment, the underlying value could still change if it's an object or array.)$inspect
: A debugging tool. Prints the current value of a signal to the console whenever it changes.
Examples:
Let's create a simple counter component using runes:
src/routes/+page.svelte
:
<script>
import { $state } from '@sveltejs/svelte'; let count = $state(0);
function increment() {
count.set(count.get() + 1);
}
function decrement() {
count.set(count.get() - 1);
}
</script>
<h1>Counter: {count.get()}</h1>
<button on:click={increment}>Increment</button>
<button on:click={decrement}>Decrement</button>
Explanation:
import { $state } from '@sveltejs/svelte';
: Imports the$state
rune. This rune is provided by the Svelte runtime library.let count = $state(0);
: Declares a reactive variable namedcount
initialized to 0.$state
takes the initial value as an argument. Critically,count
is now an object withget()
andset()
methods.
: Displays the current value ofCounter: {count.get()}
count
. Because count is a state variable we access it using itsget
methodcount.set(count.get() + 1);
: Increments the value ofcount
by 1. The.set()
method triggers reactivity. Svelte knows to update the component becausecount
is a reactive variable.
Derived Signals:
<script>
import { $state, $derived } from '@sveltejs/svelte'; let count = $state(0);
let doubled = $derived(count.get() * 2);
function increment() {
count.set(count.get() + 1);
}
</script>
<h1>Counter: {count.get()}</h1>
<h2>Doubled: {doubled.get()}</h2>
<button on:click={increment}>Increment</button>
Explanation:
- **
let doubled = $derived(count.get() * 2);
**: Creates a derived signal calleddoubled
. Its value is calculated ascount * 2
. Whenevercount
changes,doubled
is automatically updated.
Effects:
<script>
import { $state, $effect } from '@sveltejs/svelte'; let count = $state(0);
$effect(() => {
console.log("Count changed to:", count.get());
document.title = `Count: ${count.get()}`; // Example DOM manipulation
});
function increment() {
count.set(count.get() + 1);
}
</script>
<h1>Counter: {count.get()}</h1>
<button on:click={increment}>Increment</button>
Explanation:
$effect(() => { ... });
: Creates an effect. The function inside$effect
will run whenevercount
changes. In this example, it logs the new value ofcount
to the console and updates the page title.
Binding and Props (Simplified):
<!-- Parent Component (Parent.svelte) -->
<script>
import Child from './Child.svelte';
import { $state } from '@sveltejs/svelte'; let message = $state("Hello from Parent!");
let counter = $state(0);
function incrementParent() {
counter.set(counter.get() + 1);
}
</script>
<h1>Parent Component</h1>
<p>Message: {message.get()}</p>
<p>Parent Counter: {counter.get()}</p>
<button on:click={incrementParent}>Increment Parent</button>
<Child boundMessage={message} myCounter={counter} />
<!-- Child Component (Child.svelte) -->
<script>
import { $state, $effect } from '@sveltejs/svelte';
//Props are state variables, and are auto declared for runes
export let boundMessage;
export let myCounter;
let localCounter = $state(0);
$effect(() => {
console.log('Message received in Child: ', boundMessage.get());
})
function incrementChild() {
localCounter.set(localCounter.get() + 1);
}
</script>
<h2>Child Component</h2>
<p>Bound Message: {boundMessage.get()}</p>
<p>My Counter (from parent): {myCounter.get()}</p>
<p>Child Local Counter: {localCounter.get()}</p>
<button on:click={incrementChild}>Increment Child</button>
- In the Parent Component, we declare
message
andcounter
as reactive state variables with$state()
. - We pass these signals to the child component
Child
via propsboundMessage
andmyCounter
. - In the
Child.svelte
the props are declared as standard svelteexport let
variables. Because Svelte knows that the props were passed as runes it will automatically handle reactivity - We can access the values inside of the child using the
get()
method.
Common Patterns and Best Practices:
- Use
$state
sparingly. Avoid overusing$state
. Use it only for values that need to be truly reactive. For simple variables that don't need to trigger updates, use regularlet
declarations. - Use
$derived
for computed values. Whenever you have a value that depends on other reactive values, use$derived
to ensure it's automatically updated. - Effects for side effects. Use
$effect
only for side effects like DOM manipulation, logging, or fetching data. Avoid using$effect
for updating state, as it can lead to infinite loops. $const
for immutability (with caveats). Use$const
to declare constants that shouldn't be reassigned. Be aware that if the "constant" is an object or array, its contents can still be modified.- Use
.set
for modifying reactive variables. Always use the.set()
method to update reactive variables created with$state
. Direct assignment (e.g.,count = newValue;
) will not trigger reactivity. - Avoid complex logic in
$derived
. Keep the logic inside$derived
functions simple and pure. Complex logic is better placed in separate functions. - Be mindful of dependencies in
$effect
. Svelte automatically tracks the dependencies of$effect
functions. However, it's a good practice to explicitly list dependencies usingbind:
orlet:
, especially for complex components.
Example: Fetching Data
<script>
import { $state, $effect } from '@sveltejs/svelte'; let todos = $state([]);
let loading = $state(true);
let error = $state(null);
$effect(async () => {
loading.set(true);
error.set(null);
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
todos.set(data);
} catch (e) {
error.set(e.message);
} finally {
loading.set(false);
}
});
</script>
{#if loading.get()}
<p>Loading...</p>
{:else if error.get()}
<p>Error: {error.get()}</p>
{:else}
<ul>
{#each todos.get() as todo}
<li>{todo.title}</li>
{/each}
</ul>
{/if}
Key Takeaways:
- Svelte 5's runes offer a more explicit and controllable way to manage reactivity.
$
(with$state
and$derived
) and$effect
are the most commonly used runes.- Use runes judiciously, focusing on truly reactive values.
- Understand the
.get()
and.set()
methods for accessing and modifying rune based state. - Runes enable better performance and tooling.
Further Learning:
- Svelte Documentation: The official Svelte documentation is the best resource for in-depth information: https://svelte.dev/ (Pay close attention to the "5.0" or "next" documentation).
- Svelte Discord: Join the Svelte Discord community for help and discussions: https://svelte.dev/chat
- Svelte Examples: Explore real-world examples of Svelte 5 applications to learn best practices.
This tutorial provides a solid foundation for understanding Svelte 5's runes. Experiment, build projects, and explore the documentation to master this powerful new approach to Svelte development. Remember to keep checking the official Svelte documentation for updates as Svelte 5 continues to evolve.
Svelte 5 is the latest iteration of the Svelte framework, introducing significant updates and improvements over previous versions. As of now, Svelte 5 is still in preview, and its features may evolve before the final release. This tutorial will cover the basics of Svelte 5, assuming you have a fundamental understanding of web development and JavaScript. If Svelte 5 has been officially released or updated since my last knowledge update (October 2023), I recommend checking the official Svelte documentation for the latest information.
What’s New in Svelte 5?
Svelte 5 introduces several key features and improvements, including:
- Runes: A new reactivity system that replaces the old reactive statements (
$:
) with more explicit and powerful primitives like$state
,$derived
, and$effect
. - Improved Performance: Further optimizations to the compiler for faster updates and smaller bundles.
- Better TypeScript Integration: Enhanced support for TypeScript with better type inference.
- Snippets: A new way to define reusable UI components as snippets.
- Refined Reactivity Model: More intuitive and explicit control over reactivity.
This tutorial will walk you through setting up a Svelte 5 project, using Runes for reactivity, and building a simple application.
Step 1: Setting Up a Svelte 5 Project
- Install Node.js:
- Create a New Svelte Project:
degit
tool or the official SvelteKit CLI to scaffold a new Svelte 5 project. Since Svelte 5 is tied to SvelteKit for project initialization, we’ll use SvelteKit. Run the following command to create a new project:
npm create vite@latest my-svelte-app -- --template svelte
- Select "Svelte" as the framework.
- Choose whether to use TypeScript (recommended for better type safety).
- Follow the prompts to configure additional options like ESLint or Prettier.
- Navigate to the Project Directory:
cd my-svelte-app
- Install Dependencies:
npm install
- Start the Development Server:
npm run dev
Open your browser and navigate to
http://localhost:5173
(or the port specified in the terminal) to see the default Svelte starter app.Step 2: Understanding Svelte 5 Runes
Runes are the new reactivity system in Svelte 5, replacing the
$:
syntax for reactive statements. They make reactivity more explicit and easier to reason about. The primary runes are $state
, $derived
, and $effect
.Example: Using $state
for Reactive Variables
Create a new component in
src/routes/+page.svelte
and replace its content with the following:<script>
import { $state } from 'svelte'; // Declare a reactive state variable using $state
let count = $state(0);
function increment() {
count += 1; // Directly update the state
}
</script>
<h1>Counter: {count}</h1>
<button on:click={increment}>Increment</button>
$state
declares a reactive variable. Whencount
changes, the DOM automatically updates to reflect the new value.- Unlike Svelte 4, you no longer need to use
$:
for reactivity;$state
handles it explicitly.
Example: Using $derived
for Computed Values
$derived
is used to create values that depend on other reactive states.<script>
import { $state, $derived } from 'svelte'; let count = $state(0);
let doubled = $derived(count * 2); // Derived value updates when count changes
function increment() {
count += 1;
}
</script>
<h1>Counter: {count}</h1>
<h2>Doubled: {doubled}</h2>
<button on:click={increment}>Increment</button>
$derived
automatically recomputesdoubled
whenevercount
changes.
Example: Using $effect
for Side Effects
$effect
lets you run side effects (like logging or fetching data) when reactive values change.<script>
import { $state, $effect } from 'svelte'; let count = $state(0);
$effect(() => {
console.log(`Count changed to: ${count}`);
});
function increment() {
count += 1;
}
</script>
<h1>Counter: {count}</h1>
<button on:click={increment}>Increment</button>
$effect
runs whenever any reactive dependency (likecount
) changes.
Step 3: Building a Simple Todo App with Svelte 5
Let’s create a small Todo application to demonstrate Svelte 5’s features in action.
- Update
src/routes/+page.svelte
with the following code:
<script>
import { $state } from 'svelte'; // Reactive state for todos and input
let todos = $state([]);
let newTodo = $state('');
function addTodo() {
if (newTodo.trim()) {
todos = [...todos, { id: todos.length + 1, text: newTodo, done: false }];
newTodo = ''; // Reset input
}
}
function toggleTodo(id) {
todos = todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
);
}
</script>
<h1>Todo List</h1>
<input
type="text"
bind:value={newTodo}
placeholder="Add a new todo"
on:keydown={(e) => e.key === 'Enter' && addTodo()}
/>
<button on:click={addTodo}>Add</button>
<ul>
{#each todos as todo}
<li style="text-decoration: {todo.done ? 'line-through' : 'none'}">
{todo.text}
<button on:click={() => toggleTodo(todo.id)}>
{todo.done ? 'Undo' : 'Complete'}
</button>
</li>
{:else}
<p>No todos yet!</p>
{/each}
</ul>
- Run the app with
npm run dev
and interact with the Todo list by adding and toggling tasks. - The
todos
array is reactive thanks to$state
, so the UI updates automatically when items are added or modified. - The
#each
directive loops over thetodos
array to render the list.
Step 4: Using Snippets in Svelte 5
Svelte 5 introduces "snippets," which are reusable blocks of UI code. They’re similar to components but lighter and more focused on rendering markup.
Example of a snippet in src/routes/+page.svelte
:
<script>
import { $state } from 'svelte'; let name = $state('World');
// Define a reusable snippet
$: greeting = `<h2>Hello, {name}!</h2>`;
</script>
<!-- Use the snippet -->
{@render greeting}
- Snippets allow you to define reusable UI logic without creating a full component.
Step 5: Building and Deploying
- Build the app for production:
npm run build
- Preview the production build locally:
npm run preview
- Deploy to a hosting service like Vercel, Netlify, or GitHub Pages by following their respective guides for SvelteKit apps.
Additional Tips
- TypeScript Support: If you chose TypeScript during setup, ensure your editor (e.g., VS Code) has the Svelte extension installed for proper type checking.
- SvelteKit Features: Explore SvelteKit’s features like file-system-based routing, server-side rendering (SSR), and static site generation (SSG).
- Community Resources: Join the Svelte Discord or follow the official Svelte blog for updates on Svelte 5.
- Official Docs: The Svelte documentation and SvelteKit docs are excellent resources for learning more about specific features.
Conclusion
Svelte 5 brings exciting changes with Runes, snippets, and improved performance, making it an even more powerful framework for building web applications. This tutorial covered the basics of setting up a project, using the new reactivity system, and building a simple app. As Svelte 5 evolves, keep an eye on the official documentation and community for updates and best practices.
If you have specific questions or want to dive deeper into a particular feature (e.g., stores, animations, or SvelteKit routing), let me know!
💡 Try this comparison yourself:Compare AI models side-by-side on SNEOS
Analysis
This comparison demonstrates the different approaches each AI model takes when responding to the same prompt. Here are the key differences observed:
Response Characteristics
Claude: Provides a direct response with 33 sentences.
Gemini: Provides a direct response with 174 sentences.
Grok: Provides a direct response with 93 sentences.
Key Takeaways
- Each model brings unique strengths to this type of query
- Response styles vary significantly between models
- Consider your specific use case when choosing between these models
Try This Comparison Yourself
Want to test these models with your own prompts? Visit SNEOS.com to compare AI responses side-by-side in real-time.
This comparison was generated using the SNEOS AI Comparison ToolPublished: October 01, 2025 | Models: Claude, Gemini, Grok