Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/danielitoCode/compose_svelted/llms.txt

Use this file to discover all available pages before exploring further.

Compose Svelted treats navigation the same way it treats everything else: as state. The current screen is simply the top entry of a backstack array held inside a Svelte writable store. When that store changes, the NavHost component reacts and renders the new screen — no file-based routing, no SvelteKit pages, no URL parsing required. This model is intentionally inspired by Jetpack Compose’s navigation API. If you have used NavController and NavHost in Android development, the concepts map directly. If you haven’t, the mental model is straightforward: a controller owns a stack of route names, and a host renders whichever route is on top.

Why navigation as state?

Because every other piece of UI in Svelte is already reactive state, navigation should be too. There is no special lifecycle hook to intercept, no history API to manage, and no framework adapter to install. You create a controller, pass it to a host, and call navigate() from anywhere you have access to the controller. This approach works in any Svelte 5 application — standalone, embedded in a larger app, or running inside SvelteKit alongside its own router for a sub-section of the page tree.

Three core concepts

The entire navigation system is built from three primitives. Route — A plain object with a path string. Routes have no behavior of their own; they are just typed identifiers that tie a controller call to a host registration.
export type Route<T = unknown> = { path: string };
NavController — Owns and mutates the backstack. Exposes navigate() to push a new entry and popBackStack() to remove the top one. The backstack is a Svelte writable store, so anything that subscribes to it updates automatically. NavHost — A Svelte component that subscribes to the controller’s store, finds the registered component for the top entry, and renders it inside an AnimatedContent wrapper that plays the configured transition.

The full pattern at a glance

1. Define routes as typed objects

Route definitions are plain exported constants. Keeping them in a dedicated file makes imports predictable across every screen.
routes.ts
export const Login   = { path: 'login' };
export const Home    = { path: 'home' };
export const Details = { path: 'details' };

2. Create a controller with rememberNavController

Call rememberNavController with the path of the screen that should appear first. The returned NavController instance is the single source of truth for your navigation state.
import { rememberNavController } from '@danielito1996/compose-svelted';
import { Home } from './routes';

const navController = rememberNavController(Home.path);

3. Declare routes in NavHost with composable()

composable(route, factory) maps a route object to a component. Pass an array of these mappings to NavHost alongside the controller.
<NavHost
  navController={navController}
  modifier={Modifier.fillMaxSize()}
  routes={[
    composable(Login,   () => LoginScreen),
    composable(Home,    () => HomeScreen),
    composable(Details, () => DetailsScreen)
  ]}
/>

4. Navigate from any screen

Every screen registered in NavHost automatically receives navController as a prop. Call navigate() or popBackStack() directly from button handlers or any other event.
// push a new screen
navController.navigate(Details.path, { id: 42 });

// go back
navController.popBackStack();

Learn more

NavController

Backstack management: navigate, popBackStack, route types, and the rememberNavController factory.

NavHost

Declare route-to-component mappings with composable() and configure animated screen transitions.

Build docs developers (and LLMs) love