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>