Svelte Adapter
Svelte 5 with Runes, zero-runtime compiled components, native TypeScript, CSS scoping, and transitions — the fastest UI framework paired with the fastest build tool.
Svelte 5 · Runes · Zero Runtime
Svelte 5 Runes
Full Svelte 5 Runes support: $state, $derived, $effect, $props — reactivity without a virtual DOM.
Zero runtime
Svelte compiles to vanilla JS — no framework runtime in the bundle. The smallest possible output.
Scoped CSS
<style> blocks are automatically scoped to the component without any class hashing setup.
Transitions built-in
svelte/transition and svelte/animate provide GPU-accelerated enter/exit animations with zero deps.
TypeScript native
lang='ts' on script blocks. Full type-checking via svelte-check and the official VS Code extension.
Svelte stores
Reactive writable, readable, and derived stores for cross-component state sharing.
Setup
bash
npm create lunx-dev@latest my-svelte-app -- --framework svelte --ts cd my-svelte-app && npm install && npm run dev
Svelte 5 component with Runes
htmlsrc/lib/Counter.svelte
<script lang="ts"> // Svelte 5 Runes — replaces let, reactive statements, and stores let { initialCount = 0 }: { initialCount?: number } = $props() let count = $state(initialCount) let doubled = $derived(count * 2) let history = $state<number[]>([]) $effect(() => { // Runs when count changes — like useEffect but automatic history = [...history, count] console.log(`Count changed to ${count}`) }) function increment() { count++ } function decrement() { count-- } function reset() { count = initialCount } </script> <div class="counter"> <h2>Count: {count}</h2> <p>Doubled: {doubled}</p> <div class="controls"> <button onclick={decrement}>−</button> <button onclick={increment}>+</button> <button onclick={reset}>Reset</button> </div> <details> <summary>History ({history.length} changes)</summary> <ol>{#each history as n}<li>{n}</li>{/each}</ol> </details> </div> <style> .counter { display: flex; flex-direction: column; gap: 1rem; padding: 1.5rem; } .controls { display: flex; gap: 0.5rem; } button { padding: 0.5rem 1rem; border-radius: 8px; cursor: pointer; } </style>
Routing with svelte-routing
bash
npm install svelte-routinghtmlsrc/App.svelte
<script lang="ts"> import { Router, Route, Link } from 'svelte-routing' import Home from '@/pages/Home.svelte' import About from '@/pages/About.svelte' import Profile from '@/pages/Profile.svelte' </script> <Router> <nav> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/profile">Profile</Link> </nav> <main> <Route path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/profile" component={Profile} /> </main> </Router>
Svelte stores for state
typescriptsrc/lib/stores/cart.ts
import { writable, derived, get } from 'svelte/store' export interface CartItem { id: string name: string price: number quantity: number } // Writable store — mutable state export const cartItems = writable<CartItem[]>([]) // Derived store — computed from cartItems export const cartTotal = derived( cartItems, $items => $items.reduce((sum, item) => sum + item.price * item.quantity, 0) ) export const cartCount = derived( cartItems, $items => $items.reduce((sum, item) => sum + item.quantity, 0) ) // Actions export function addToCart(item: Omit<CartItem, 'quantity'>) { cartItems.update(items => { const existing = items.find(i => i.id === item.id) if (existing) { return items.map(i => i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i) } return [...items, { ...item, quantity: 1 }] }) } export function removeFromCart(id: string) { cartItems.update(items => items.filter(i => i.id !== id)) }
Svelte transitions
htmlsrc/lib/Toast.svelte
<script lang="ts"> import { fly, fade } from 'svelte/transition' import { flip } from 'svelte/animate' interface Toast { id: number; message: string; type: 'success' | 'error' } let { toasts }: { toasts: Toast[] } = $props() </script> {#each toasts as toast (toast.id)} <div class="toast toast--{toast.type}" animate:flip={{ duration: 200 }} in:fly={{ y: 20, duration: 300 }} out:fade={{ duration: 200 }} > {toast.message} </div> {/each}
Svelte 4 compatibility
Lunx supports both Svelte 4 (reactive declarations with
$:) and Svelte 5 (Runes). The adapter auto-detects your installed Svelte version. You can mix Svelte 4 and Svelte 5 components in the same project during migration.