Svelte and SvelteKit course ยท Module 11: SvelteKit Routing
Error Pages and Special Pages
In this lesson4
+error.svelte
<!-- src/routes/+error.svelte -->
<script>
import { page } from '$app/state';
</script>
<h1>Error {page.status}</h1>
<p>{page.error?.message}</p>
<a href="/">Back to the home page</a>The page object from $app/state is reactive and you read it without a $ sign. The old $page store from the $app/stores module was removed in SvelteKit 3.
Raising errors
// src/routes/warriors/[id]/+page.js
import { error } from '@sveltejs/kit';
export function load({ params }) {
const warrior = getWarrior(params.id);
if (!warrior) {
error(404, 'Warrior not found');
}
return { warrior };
}The error() function throws by itself, so you do not write throw in front of it (that was the SvelteKit 1 form). The second argument is always the message text.
+page.js vs +page.server.js
// +page.js - runs on server AND client
export function load({ params, fetch }) {
// Can be called during client-side navigation
return { data };
}// +page.server.js - server ONLY
export function load({ params, locals }) {
// Access to database, secrets, etc.
return { data };
}Redirects
import { redirect } from '@sveltejs/kit';
export function load({ locals }) {
if (!locals.user) {
redirect(303, '/login');
}
return { user: locals.user };
}Just like error(), redirect() throws by itself - no throw needed.
Code for this lesson: App.svelte
<script>
// Programmatic navigation and loading states
let loading = $state(false);
let currentPage = $state('home');
async function navigateTo(page) {
loading = true;
// Simulating data loading
await new Promise(r => setTimeout(r, 1000));
currentPage = page;
loading = false;
}
// Simulating beforeNavigate
function handleBeforeNavigate(e, page) {
if (currentPage === 'form' && !confirm('Leave the page?')) {
e.preventDefault();
return;
}
navigateTo(page);
}
</script>
<main class="navigation-demo">
<h1>SvelteKit Navigation</h1>
<nav class="nav">
<button onclick={(e) => handleBeforeNavigate(e, 'home')}>Home</button>
<button onclick={(e) => handleBeforeNavigate(e, 'warriors')}>Warriors</button>
<button onclick={(e) => handleBeforeNavigate(e, 'form')}>Form</button>
</nav>
{#if loading}
<div class="loading">
<div class="spinner"></div>
<p>Loading...</p>
</div>
{:else}
<section class="content">
{#if currentPage === 'home'}
<h2>Home page</h2>
<p>Welcome to the app!</p>
{:else if currentPage === 'warriors'}
<h2>Warriors</h2>
<p>List loaded from server</p>
{:else if currentPage === 'form'}
<h2>Form</h2>
<p>Leaving will cause data loss!</p>
<input placeholder="Type something..." />
{/if}
</section>
{/if}
<section class="code-example">
<h2>Programmatic navigation</h2>
<pre>
import {"{"} goto {"}"} from '$app/navigation';
// Simple navigation
goto('/warriors');
// With options
goto('/warriors', {"{"}
replace: true,
refreshAll: true
{"}"});
</pre>
</section>
</main>
<style>
.navigation-demo {
font-family: 'Georgia', serif;
max-width: 600px;
margin: 0 auto;
padding: 2rem;
background: #0a1628;
color: #b8d4f7;
min-height: 100vh;
}
h1 {
color: #4a90d9;
text-align: center;
}
.nav {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 2rem;
}
button {
padding: 0.75rem 1.5rem;
background: #1e3a5f;
color: #b8d4f7;
border: 1px solid #4a90d9;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #2a4a6f;
}
.loading {
text-align: center;
padding: 3rem;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid #1e3a5f;
border-top-color: #4a90d9;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
section {
background: rgba(74, 144, 217, 0.1);
border: 1px solid #4a90d9;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
h2 {
color: #4a90d9;
margin-top: 0;
}
input {
width: 100%;
padding: 0.75rem;
background: rgba(0,0,0,0.3);
border: 1px solid #4a90d9;
border-radius: 4px;
color: #b8d4f7;
margin-top: 0.5rem;
}
pre {
background: rgba(0,0,0,0.5);
padding: 1rem;
border-radius: 4px;
font-size: 0.85rem;
overflow-x: auto;
}
</style>Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. How do you raise a 404 error in a load function (SvelteKit 3)?