The React Router experience, reimagined for Svelte with declarative routing and data loading patterns.
Uses the HTML5 History API for clean URLs (/profile)
<script lang="ts">
import { Routes, Route, BrowserRouter, HashRouter, MemoryRouter } from "$lib/index.js";
import { browser } from "$app/environment";
import type { RouterType } from "$components/showcase.svelte";
import Home from "./home.svelte";
import Profile from "./profile.svelte";
import Settings from "./settings.svelte";
interface DeclarativeRouterProps {
routerType: RouterType;
}
let { routerType }: DeclarativeRouterProps = $props();
</script>
{#if routerType === "browser" && browser}
<BrowserRouter children={routes} />
{:else if routerType === "hash" && browser}
<HashRouter children={routes} />
{:else}
<MemoryRouter children={routes} />
{/if}
{#snippet routes()}
<Routes>
<Route path="/" Component={Home} />
<Route path="/profile" Component={Profile} />
<Route path="/settings" Component={Settings} />
<Route path="*">
{#snippet element()}
<div class="text-center py-8">
<h2 class="text-xl font-bold mb-2">404 - Page Not Found</h2>
<p class="text-muted-foreground">The page you're looking for doesn't exist.</p>
</div>
{/snippet}
</Route>
</Routes>
{/snippet}
<script lang="ts">
import { useNavigate, useLocation, Link } from "$lib/index.js";
import { fly } from "svelte/transition";
import Home from "~icons/lucide/home";
import ArrowRight from "~icons/lucide/arrow-right";
import { Button } from "$ui/button/index.js";
let navigate = useNavigate();
let location = $derived(useLocation());
</script>
<div in:fly={{ y: 20, duration: 300 }} class="space-y-6">
<div class="flex items-center gap-3">
<Home class="w-6 h-6 text-blue-500" />
<h1 class="text-2xl font-bold">Home Page</h1>
</div>
<div class="bg-muted/50 rounded-lg p-4 space-y-3">
<p class="text-sm text-muted-foreground">Current location:</p>
<code class="block bg-background rounded px-3 py-2 text-sm font-mono">
{location.pathname}
</code>
</div>
<div class="space-y-4">
<p>
Welcome to the declarative routing demo! This demonstrates how routes are defined
declaratively using Route components.
</p>
<div class="flex gap-3">
<Link to="/profile">
{#snippet child({ props })}
<Button {...props} class="flex items-center gap-2">
View Profile
<ArrowRight class="w-4 h-4" />
</Button>
{/snippet}
</Link>
<!-- or -->
<Button variant="outline" onclick={() => navigate("/settings")}>Settings</Button>
</div>
</div>
<div class="text-xs text-muted-foreground">
This page demonstrates declarative routing with navigation hooks.
</div>
</div>
<script lang="ts">
import { useNavigate, useLocation } from "$lib/index.js";
import { fly } from "svelte/transition";
import User from "~icons/lucide/user";
import ArrowLeft from "~icons/lucide/arrow-left";
import Settings from "~icons/lucide/settings";
import { Button } from "$ui/button/index.js";
let navigate = useNavigate();
let location = $derived(useLocation());
// Simulate user data
const userData = {
name: "Jane Doe",
email: "jane@example.com",
role: "Developer",
joinDate: "2023-01-15",
};
</script>
<div in:fly={{ y: 20, duration: 300 }} class="space-y-6">
<div class="flex items-center gap-3">
<User class="w-6 h-6 text-green-500" />
<h1 class="text-2xl font-bold">Profile</h1>
</div>
<div class="bg-muted/50 rounded-lg p-4 space-y-3">
<p class="text-sm text-muted-foreground">Current location:</p>
<code class="block bg-background rounded px-3 py-2 text-sm font-mono">
{location.pathname}
</code>
</div>
<div class="bg-card border border-border rounded-lg p-6 space-y-4">
<h2 class="text-lg font-semibold">User Information</h2>
<div class="grid grid-cols-2 gap-4 text-sm">
<div>
<span class="font-medium text-muted-foreground">Name:</span>
<p>{userData.name}</p>
</div>
<div>
<span class="font-medium text-muted-foreground">Email:</span>
<p>{userData.email}</p>
</div>
<div>
<span class="font-medium text-muted-foreground">Role:</span>
<p>{userData.role}</p>
</div>
<div>
<span class="font-medium text-muted-foreground">Join Date:</span>
<p>{userData.joinDate}</p>
</div>
</div>
</div>
<div class="flex gap-3">
<Button onclick={() => navigate("/")} variant="outline" class="flex items-center gap-2">
<ArrowLeft class="w-4 h-4" />
Back to Home
</Button>
<Button onclick={() => navigate("/settings")} class="flex items-center gap-2">
<Settings class="w-4 h-4" />
Settings
</Button>
</div>
<div class="text-xs text-muted-foreground">
This page demonstrates declarative routing with static data.
</div>
</div>
<script lang="ts">
import { useNavigate, useLocation } from "$lib/index.js";
import { fly } from "svelte/transition";
import Settings from "~icons/lucide/settings";
import ArrowLeft from "~icons/lucide/arrow-left";
import User from "~icons/lucide/user";
import { Button } from "$ui/button/index.js";
let navigate = useNavigate();
let location = $derived(useLocation());
let darkMode = $state(false);
let notifications = $state(true);
let autoSave = $state(true);
</script>
<div in:fly={{ y: 20, duration: 300 }} class="space-y-6">
<div class="flex items-center gap-3">
<Settings class="w-6 h-6 text-purple-500" />
<h1 class="text-2xl font-bold">Settings</h1>
</div>
<div class="bg-muted/50 rounded-lg p-4 space-y-3">
<p class="text-sm text-muted-foreground">Current location:</p>
<code class="block bg-background rounded px-3 py-2 text-sm font-mono">
{location.pathname}
</code>
</div>
<div class="bg-card border border-border rounded-lg p-6 space-y-6">
<h2 class="text-lg font-semibold">Preferences</h2>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div>
<h3 class="font-medium">Dark Mode</h3>
<p class="text-sm text-muted-foreground">Switch to dark theme</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" bind:checked={darkMode} class="sr-only peer" />
<div
class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"
></div>
</label>
</div>
<div class="flex items-center justify-between">
<div>
<h3 class="font-medium">Notifications</h3>
<p class="text-sm text-muted-foreground">Receive push notifications</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" bind:checked={notifications} class="sr-only peer" />
<div
class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"
></div>
</label>
</div>
<div class="flex items-center justify-between">
<div>
<h3 class="font-medium">Auto Save</h3>
<p class="text-sm text-muted-foreground">Automatically save changes</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" bind:checked={autoSave} class="sr-only peer" />
<div
class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"
></div>
</label>
</div>
</div>
</div>
<div class="flex gap-3">
<Button onclick={() => navigate("/")} variant="outline" class="flex items-center gap-2">
<ArrowLeft class="w-4 h-4" />
Back to Home
</Button>
<Button onclick={() => navigate("/profile")} variant="outline" class="flex items-center gap-2">
<User class="w-4 h-4" />
Profile
</Button>
</div>
<div class="text-xs text-muted-foreground">
This page demonstrates declarative routing with interactive components.
</div>
</div>