Router factory


Import

import {
createRouter,
defineRoute,
defineRoutes,
eagerPreload,
intentPreload,
pendingLinks,
tapPreload,
viewportPreload,
} from "@solidjs/router";

createRouter

Creates an immutable router instance from a route tree.

function createRouter<const R extends readonly RouteDefinition[]>(
config: RouterConfig<R>
): RouterInstance<R>;

RouterConfig

interface RouterConfig<
R extends readonly RouteDefinition[] = RouteDefinition[],
> {
routes: R;
base?: string;
preload?: RoutePreloadFunc;
history?: RouterHistory;
singleFlight?: boolean;
actionBase?: string;
explicitLinks?: boolean;
links?: LinksPlugin;
preloadLinks?: LinkPreload | readonly LinkPreload[];
scrollRestoration?: boolean;
transformUrl?: (url: string) => string;
}
  • routes is the route tree used for matching and path inference.
  • base prefixes matched and generated paths.
  • preload returns data for the root render prop.
  • history defaults to browser history on the client.
  • singleFlight defaults to true.
  • actionBase defaults to /_server.
  • explicitLinks defaults to false.
  • links adds state to claimed anchors. Pass pendingLinks for data-pending. Client-only.
  • preloadLinks takes one link preload strategy or an array of them. Links do not preload by default. Client-only.
  • scrollRestoration defaults to true with the default browser history.
  • transformUrl rewrites pathnames before matching and preloading.

Return value

interface RouterInstance<
R extends readonly RouteDefinition[] = RouteDefinition[],
> {
(props: RouterProps): JSX.Element;
readonly paths: RoutePaths<R>;
readonly routes: R;
readonly config: RouterConfig<R>;
match(url: string): OutputMatch[];
}

The instance is the provider component. paths is created on first access. match(url) returns root-to-leaf matches or an empty array.

const Router = createRouter({
routes: [{ path: "/", component: Home }],
});
<Router>{(props) => <main>{props.children}</main>}</Router>;

RouterProps

interface RouterProps {
url?: string;
children?: (props: RouteSectionProps) => JSX.Element;
}

url selects a server-rendered location when no request event exists. A request event takes precedence. The client ignores url.


A LinkPreload is a strategy for the preloadLinks option. It runs once under the router's owner on the client and cleans up with it. Each strategy warms the link's route code, and runs the matched routes' preload functions when data is true. A link with preload="false" is never preloaded.

type LinkPreload = (ctx: LinkPreloadContext) => void;
const Router = createRouter({
routes,
preloadLinks: [intentPreload(), viewportPreload()],
});

intentPreload

function intentPreload(options?: {
delay?: number;
data?: boolean;
}): LinkPreload;

Preloads a link when the pointer rests on it for delay ms (default 20), when it takes focus, and on touchstart. A link preloads once per visit, whichever of these comes first. data defaults to true.

tapPreload

function tapPreload(options?: { data?: boolean }): LinkPreload;

Preloads a link on pointerdown, ahead of its click. data defaults to true.

viewportPreload

function viewportPreload(options?: {
all?: boolean;
data?: boolean;
delay?: number;
rootMargin?: string;
}): LinkPreload;

Preloads a link once it has stayed in the viewport for delay ms (default 100), when the browser is next idle. Each link preloads once, and again after its href changes. Applies to links with preload="viewport", or with all: true to every link except preload="false". rootMargin is passed to the shared IntersectionObserver. data defaults to false. Skips preloading when the browser reports Save-Data or a 2g connection.

eagerPreload

function eagerPreload(options?: { all?: boolean; data?: boolean }): LinkPreload;

Preloads links once the page has loaded and the browser is idle, including links mounted later. Applies to links with preload="eager", or with all: true to every link except preload="false". data defaults to false. Skips preloading when the browser reports Save-Data or a 2g connection.


A LinksPlugin that adds data-pending to claimed anchors whose path covers the in-flight destination of a link click or navigate() call. Back and forward navigation does not set it. The attribute is removed when the navigation lands.

const pendingLinks: LinksPlugin;
const Router = createRouter({ routes, links: pendingLinks });
a[data-pending] {
opacity: 0.6;
}

useLinkState().pending works without this plugin.

LinksPlugin

type LinksPlugin = (
router: RouterContext,
base: string
) => {
track(): unknown;
pending(target: string | undefined): boolean;
};

The router builds the plugin once with its base path. The claims sweep re-runs when track() changes, and reads pending(target) for each anchor while track() is truthy.


defineRoutes

Preserves literal types for an extracted route tuple and returns the same value.

function defineRoutes<const R extends readonly RouteDefinition[]>(routes: R): R;
const routes = defineRoutes([{ path: "/" }, { path: "/users/:id" }]);

defineRoute

Returns the supplied route object while typing its component and preload parameters from its path.

function defineRoute<
const S extends string | readonly string[],
T = unknown,
const F = DefinedRouteFilters<S>,
const C extends RouteChildren | undefined = RouteChildren | undefined,
Sch extends StandardSchemaV1<any, any> | undefined = undefined,
>(route: {
path: S;
matchFilters?: F;
preload?: (args: RoutePreloadFuncArgs<RouteParams<S>>) => T;
component?: (
props: RouteSectionProps<T, RouteParams<S>> & { children?: any }
) => JSX.Element;
children?: C;
search?: Sch;
info?: RouteInfo;
}): DefinedRoute<S, T, F, C, Sch>;

RouteChildren is RouteDefinition | readonly RouteDefinition[] | LazyRouteChildren. A pathless overload omits path and uses open Params.

const route = defineRoute({
path: "/users/:id",
preload: ({ params }) => getUser(params.id),
component: (props) => <h1>{props.data.name}</h1>,
});

Last updated: 10/15/26, 9:29 AMEdit this pageReport an issue with this page