SvelteKit Routing Essentials
Introduction to SvelteKit Routing
In the previous lessons, you've built a sophisticated Kanban board with enhanced drag-and-drop interactions, complete with drag handles, same-column reordering, smooth animations, and user preference controls. Your application now provides an excellent single-page experience where users can manage their tasks efficiently within the board view. However, as your application grows in complexity and functionality, users will benefit from having multiple ways to view and interact with their tasks.
SvelteKit's file-based routing system transforms your single-page application into a multi-page experience while maintaining the reactive, client-side performance you've already achieved. File-based routing means that the structure of your src/routes directory directly corresponds to the URLs in your application. This approach is intuitive, scalable, and eliminates the need for complex route configuration files that you might find in other frameworks.
The routing system we'll implement in this lesson will provide three distinct views of your task data. The main board view at the root URL (/) will continue to showcase your enhanced drag-and-drop functionality, allowing users to organize tasks visually across columns. A comprehensive tasks list view at /tasks will present all tasks in a tabular format, making it easy to scan through large numbers of tasks and access detailed information quickly. Individual task detail pages at /tasks/[id] will provide focused views of specific tasks, complete with metadata, full descriptions, and action buttons for status changes.
These multiple views serve different user needs and workflows. The board view excels at visual task organization and quick status updates through drag and drop. The list view is ideal for reviewing task details, searching through tasks, and getting an overview of all work items. The detail view provides a focused environment for reading full task descriptions, understanding task history, and making deliberate status changes without the visual complexity of the full board.
SvelteKit's routing system integrates seamlessly with the reactive features you've already implemented. Your task store, notification system, theme preferences, and drag-and-drop enhancements will work consistently across all routes. The routing system preserves application state as users navigate between views, ensuring that theme settings, drag preferences, and task data remain consistent throughout the user experience.
The implementation approach we'll take builds incrementally on your existing code structure. We'll start by creating a shared layout that provides navigation and maintains global functionality across all pages. Then we'll convert your existing main page to use the proper routing structure while preserving all existing functionality. Finally, we'll add the new list and detail views that extend your application's capabilities without disrupting the core features you've already built.
Understanding SvelteKit File Types
Before diving into implementation, it's important to understand the different types of files that SvelteKit uses for routing and data loading. SvelteKit provides several file types that serve different purposes in your application architecture, each with specific capabilities and execution contexts.
Page Files (+page.js vs +page.server.js)
The +page.js file runs on both the client and server, making it ideal for universal data loading logic that doesn't require server-specific resources. This file type is perfect for simple data transformations, URL parameter parsing, and client-side data preparation. The code in +page.js must be compatible with both browser and server environments, so it cannot use browser-specific APIs like localStorage or server-specific APIs like file system access.
In contrast, +page.server.js runs exclusively on the server, giving you access to databases, file systems, environment variables, and other server-only resources. This file type is essential for loading sensitive data, performing authentication checks, or executing operations that should never be exposed to the client. Data returned from +page.server.js is automatically serialized and sent to the client, where it becomes available as props to your page component.
Layout Files (+layout.js vs +layout.server.js)
Similarly, +layout.js runs on both client and server and is used for loading data that should be available to all child routes. This is ideal for loading user preferences, theme settings, or other application-wide data that doesn't require server-specific access. The data from layout load functions is available to all nested pages and layouts.
The +layout.server.js file runs only on the server and is perfect for loading sensitive application-wide data like user authentication status, server configuration, or data that requires database access. This data is serialized and made available to all child routes, just like +layout.js, but with the security and capabilities of server-side execution.
For our Kanban application, we'll primarily use +page.js files since our data is stored in localStorage and doesn't require server-side processing. However, understanding these different file types prepares you for future enhancements where you might add user authentication, database storage, or server-side rendering optimizations.
Understanding Layout Components in SvelteKit
The layout system in SvelteKit provides a powerful way to share common elements and functionality across multiple pages in your application. The +layout.svelte file serves as a wrapper around all pages in your application, making it the perfect place to implement navigation, global styles, and shared state management.
This approach ensures consistency across your application while avoiding code duplication. Every page in your application will automatically be wrapped by the layout component, which means any navigation, styling, or functionality you implement in the layout will be available on every page.
The layout component receives a special children prop that represents the content of individual pages that will be rendered within this layout structure. The {@render children?.()} syntax is Svelte 5's approach to rendering child content, with the optional chaining ensuring the layout works even if no children are provided.
Let's start creating our shared layout. Create or update your src/routes/+layout.svelte file with the basic structure:
The theme initialization remains in the layout's onMount function, ensuring that your theme system works consistently across all pages. This is important because the layout component is instantiated once and persists as users navigate between pages, making it the ideal place for global initialization logic.
Implementing Navigation with Active States
Setting Up Global Styles and Theme Integration
The layout component is also the perfect place to establish global styles that will apply across all pages in your application. These styles ensure that your existing components continue to work correctly within the new routing structure.
Add the styling section to your +layout.svelte file:
The CSS structure creates a full-height application layout with a fixed navigation bar at the top and a flexible main content area below. The navigation styling uses your existing CSS custom properties to maintain visual consistency with the theme system you implemented in earlier lessons.
The global styles section preserves all the theming work you've done in previous lessons. These styles use the :global() modifier to apply across all components in your application, ensuring that your task cards, columns, forms, and other elements maintain their themed appearance regardless of which page they appear on.
Converting the Main Page to Use Routing
With the layout structure in place, we need to update your existing main page to work properly within the new routing system. This involves adding page-specific metadata and ensuring all your existing components integrate correctly.
Update your src/routes/+page.svelte file:
The main changes here involve the addition of the <svelte:head> element and ensuring that all your existing components work within the new page structure. The <svelte:head> element allows you to set page-specific metadata like titles, which improves SEO and provides better browser tab titles for users. This page maintains all the functionality you've built in previous lessons, including the enhanced drag-and-drop system, user preferences, and theme support.
Creating the Tasks List Page Structure
Now let's create the new tasks list page that provides a different view of your task data. This page will combine tasks from all columns into a single table view, making it easy to scan through all tasks at once.
Create a new file src/routes/tasks/+page.svelte with the basic structure:
This tasks list page demonstrates important concepts in SvelteKit routing and Svelte 5 reactivity. The $derived rune creates a reactive computation that automatically combines tasks from all three status categories whenever the underlying task data changes. This ensures that the list view always shows current data without requiring manual updates or complex state management.
Adding Empty State Handling to Tasks List
A crucial user experience consideration is handling the case where no tasks exist. When users first visit the application or when all tasks have been deleted, the table view should gracefully display a helpful message rather than showing an empty table.
Let's add the empty state handling to the tasks list page:
The empty state handling prevents the jarring experience of seeing an empty table and guides users toward productive actions. The link back to the board page provides a clear path for users to create their first task, making the interface helpful rather than confusing.
Building the Tasks Table Interface
Now let's implement the actual table that will display all tasks in a comprehensive, scannable format. The table will include links to individual task detail pages and provide status information at a glance.
Add the table structure to your tasks list page:
The table structure provides a comprehensive view of all tasks with columns for title, status, creation date, and actions. Each task title links to the individual task detail page using SvelteKit's standard anchor tag approach. The status badges use conditional classes to provide visual distinction between different task states, maintaining consistency with your existing design system.
The links to individual task detail pages (/tasks/{task.id}) demonstrate how SvelteKit handles dynamic routing. These links will work automatically once we implement the dynamic route in the next sections.
Here's how the completed tasks list page will look:
.png)
Styling the Tasks Table Interface
The table needs comprehensive styling to integrate with your existing design system and provide a professional appearance. Let's add all the CSS that will make the table both functional and visually appealing.
Add these styles to your src/routes/tasks/+page.svelte file:
The responsive table container ensures that the table works well on mobile devices by allowing horizontal scrolling when necessary. The hover effects on table rows provide visual feedback that enhances the user experience, while the themed styling ensures the table integrates seamlessly with your existing color scheme.
The status badge styling maintains consistency with your existing design system, using the same color schemes you've established for different task states throughout your application.
Creating the Dynamic Route Load Function
Dynamic routes in SvelteKit allow you to create pages that respond to variable URL segments, such as individual task detail pages that display different content based on the task ID in the URL. This functionality enables deep linking, where users can bookmark or share links to specific tasks.
The dynamic route structure uses square brackets in the filename to indicate variable segments. For our task detail pages, we'll create a [id] directory within the tasks route, which will match any URL pattern like /tasks/1, /tasks/42, or /tasks/any-value. SvelteKit automatically extracts these parameters and makes them available to your page components.
Let's start by creating the load function that will extract the task ID from the URL and prepare it for use in the page component. Create a new file src/routes/tasks/[id]/+page.js:
The load function is a special SvelteKit function that runs before the page component is rendered. It receives a params object containing all the dynamic route parameters — in this case, the id from the URL. The function converts the string ID to an integer and returns it as taskId, making it available to the page component as a prop.
The load function also imports the error helper from SvelteKit, which we'll use to handle cases where invalid task IDs are provided. This approach ensures that your application handles edge cases gracefully and provides appropriate error messages to users.
Building the Task Detail Page Component
Now let's create the main task detail page component that will display comprehensive information about a specific task. This page needs to handle loading states, error cases, and provide functionality for updating task status.
Create src/routes/tasks/[id]/+page.svelte with the script section:
This task detail page demonstrates several advanced concepts in SvelteKit routing and Svelte 5 state management. The component receives the data prop from the load function, which contains the parsed task ID. The $state runes manage the local component state for the task data and loading status, providing reactive updates when the task information changes.
The onMount function handles the task lookup logic, searching through the tasks array to find the task with the matching ID. If no task is found, the component throws a SvelteKit error with a 404 status code, which will display an appropriate error page to the user.
Implementing Task Detail Templates and Actions
Now let's create the template that will display the task information and provide action buttons for status changes. The template needs to handle loading states, display task metadata, and provide intuitive controls.
Add the template section to your task detail page:
The date formatting function provides human-readable date displays with proper error handling. The status change functionality integrates with your existing task store, allowing users to update task status directly from the detail view. The action buttons are conditionally rendered based on the current task status, preventing users from moving a task to its current status.
Styling the Task Detail Interface
The task detail page needs comprehensive styling to create a focused, professional interface for viewing and managing individual tasks. Let's add all the CSS that will make the detail page both functional and visually appealing.
Add these styles to your src/routes/tasks/[id]/+page.svelte file:
The styling creates a focused, card-based layout that emphasizes the task content while providing clear visual hierarchy. The metadata section uses a flexible layout that adapts to different screen sizes, and the status badges maintain consistency with your existing design system.
The action buttons are styled to integrate with your theme system while remaining clearly actionable. The back button uses muted colors to indicate it's a secondary action, while the status change buttons use your primary theme colors to indicate their importance.
Here's how the completed task detail page will look:
.png)
Implementing Programmatic Navigation
The routing system provides the foundation for navigation, but creating a smooth user experience requires thoughtful implementation of navigation patterns and user feedback. SvelteKit provides several tools for programmatic navigation that enhance the user experience beyond basic link clicking.
The goto function from $app/navigation enables programmatic navigation, which is essential for implementing features like back buttons, form submissions that redirect to new pages, and conditional navigation based on user actions. This function provides more control than simple anchor tags and integrates seamlessly with SvelteKit's client-side routing system.
The back button we implemented in the task detail page already demonstrates basic programmatic navigation, but we can improve the user experience by making navigation more intelligent and context-aware.
Update the goBack function in your task detail page to provide smarter navigation:
This enhanced navigation function attempts to determine where the user came from and navigates accordingly. While this example defaults to the tasks list, you could extend this logic to handle more complex navigation scenarios based on your application's needs.
The navigation system should also preserve user preferences and application state as users move between pages. Your existing theme system and drag preferences are already handled by the layout component, ensuring consistent behavior across all routes.
Enhancing Layout with Global Notifications
The notification system you built in earlier lessons should work consistently across all pages. Rather than including the NotificationManager component on each individual page, we can move it to the layout component to ensure notifications are visible regardless of which page the user is viewing.
Update your src/routes/+layout.svelte file to include global notifications:
This approach ensures that notifications are always visible and don't get lost when users navigate between pages. The notification system will continue to work with your existing task operations, providing consistent feedback regardless of which view the user is currently viewing.
The active navigation states in your layout component provide important visual feedback about the current location within your application. The implementation uses $page.url.pathname to determine the current route and applies the active class accordingly.
Here's how the navigation will look with active states:
.png)
Adding Navigation Loading States
You can enhance the navigation experience further by adding loading states during route transitions. SvelteKit provides a navigating store that indicates when navigation is in progress, which is particularly useful for slower connections or when loading large amounts of data.
Add this loading indicator to your layout file:
Add the corresponding CSS for the loading indicator:
This loading indicator provides visual feedback during route transitions and can be styled to match your existing design system. The loading bar is positioned at the top of the viewport for maximum visibility and uses your theme's primary color for consistency.
The routing system preserves your enhanced drag-and-drop functionality on the board page while providing alternative views for different use cases. Users can switch between the visual board interface and the detailed list view based on their current needs, with all functionality remaining consistent across views.
Summary and Practice Preparation
