Lynx/Modules/Navigation/API reference
@sigx/lynx-navigation · Stable · Component library

API reference#

Every export of @sigx/lynx-navigation — functions, hooks, components and types.

The package is ESM-only with a single entry point (.). All inference flows from augmenting the Register interface with your route map; see Usage for the setup pattern.

Functions#

defineRoutes#

TypeScript
function defineRoutes<const T extends RouteMap>(routes: T): T

Defines a typed route registry. Returns its input verbatim — it exists purely for TypeScript inference, narrowing to a literal route map so useNav, useParams and <Link> can infer route names and per-route param/search schemas.

hrefFor#

TypeScript
function hrefFor<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>): Href<K>;
function hrefFor<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>): Href<K>;

Builds a typed Href for a route, validating params and search against the route's schema at runtime (throws on validation failure). Overloaded by whether the route declares a params schema. Requires an active route registry (a mounted NavigationRoot, or _setRouteRegistry in tests). The returned url is null when the route has no path template.

parseHref#

TypeScript
function parseHref(url: string): Href | null

Parses a URL string (absolute scheme://… or pathname-only) into a typed Href against the registered routes' path templates. Returns null when no path matches or params/search fail validation. First registration-order match wins. Takes only (url) at runtime.

compilePath#

TypeScript
function compilePath(template: string): CompiledPath

Compiles a path template (e.g. '/users/:id') into a CompiledPath with a regex and a format() method. Supports literal segments, :name params (matching [^/]+) and tolerated trailing slashes. Throws on an empty / non-string template or duplicate param names. Pure and memoizable. No wildcards, optional or typed params in v1.

_setRouteRegistry#

TypeScript
function _setRouteRegistry(routes: RouteMap): void

Test / integration use, not part of the supported public API. Imperatively seeds the module-level URL bridge registry (for tests or deep-link bootstrap before a NavigationRoot mounts). Last write wins; NavigationRoot calls this on setup.

_clearRouteRegistry#

TypeScript
function _clearRouteRegistry(): void

Test use, not part of the supported public API. Clears the module-level URL bridge route registry.

Hooks#

useNav#

TypeScript
const useNav: () => Nav

Accesses the innermost navigator handle, provided by NavigationRoot. Returns a Nav with reactive read getters (current, stack, canGoBack) and mutators (push, replace, pop, popTo, popToRoot, reset, dismiss). Throws when no NavigationRoot is mounted.

useParams#

TypeScript
function useParams<K extends RouteId>(_name: K): RouteParams<K>

Reads typed params for the current screen, asserted against the named route. The name argument is a compile-time discriminator — a wrong route name is a TS error. Snapshot at setup (screens remount on navigation).

useSearch#

TypeScript
function useSearch<K extends RouteId>(_name: K): RouteSearch<K>

Reads typed search / query params for the current screen, asserted against the named route. The name argument is a compile-time discriminator. Snapshot at setup.

useHardwareBack#

TypeScript
function useHardwareBack(): void

Wires the Android hardware / system back button to the active navigator. Idempotent per nav tree (first registration wins). No-op on iOS and in non-native runtimes. NavigationRoot auto-wires this by default — call it only when you set hardwareBack={false}. Platform: Android.

useLinkingNav#

TypeScript
function useLinkingNav(opts: UseLinkingNavOptions = {}): void

Bridges @sigx/lynx-linking URL events (cold-start getInitialURL plus warm-start 'url' events) into the navigator via parseHref. Call once inside a NavigationRoot subtree. Requires the optional @sigx/lynx-linking peer.

useIsFocused#

TypeScript
function useIsFocused(): Computed<boolean>

Returns a reactive Computed<boolean> (read .value) — true while this screen is the visible top of its navigator and every ancestor (parent entry plus enclosing tab) is focused. Must be called inside a route component rendered by Stack; throws otherwise.

useFocusEffect#

TypeScript
function useFocusEffect(cb: () => void | (() => void)): void

Runs cb when the screen gains focus and runs its returned cleanup on blur or unmount. Re-runs on each focus return. Use for analytics, subscriptions or video playback while visible.

useScreenOptions#

TypeScript
function useScreenOptions(optionsOrFn: ScreenOptions | (() => ScreenOptions)): void

Imperatively merges ScreenOptions (title, header / gesture flags, sheet options) into the current entry. A plain object merges once; a function is a tracked effect that re-merges on signal change. Strictly additive (per-key writes).

useScreenChrome#

TypeScript
function useScreenChrome(): ScreenChrome

Reactive read of the focused screen's options and slot fills, plus header helpers (title, headerShown, canGoBack, pop, header, headerLeft, headerRight). The public foundation for custom header components; every property is a getter. Resolves to the scoped entry inside an EntryScope, otherwise to the navigator's destination entry.

useNavSerializer#

TypeScript
function useNavSerializer(options: UseNavSerializerOptions): void

Persists the navigator's root stack across launches via a NavStorageAdapter. On mount it loads and validates (version / shape / unknown-route) then applies with nav.reset(); it subscribes to nav.stack and saves debounced (default 250 ms). Only the root navigator is persisted in v1 (nested / per-tab stacks are not yet).

useTabs#

TypeScript
const useTabs: () => TabsNav

Accesses the enclosing Tabs navigator: { active, setActive(name), tabs }. Reactive. Throws when called outside Tabs. setActive ignores unknown tab names (no-op).

useDrawer#

TypeScript
const useDrawer: () => DrawerNav

Accesses the enclosing Drawer navigator: { isOpen, open(), close(), toggle() }. Reactive. Throws when called outside Drawer.

Components#

Each component has its own page with usage, props, slots and events — see the Components catalog:

  • Stack — the stack navigator; renders the enclosing stack in bound mode or mints a fresh nested navigator (per-tab back-stacks) in nested-owner mode.
  • Tabs — a persistent tab navigator hosting <Tabs.Screen>; tab bodies stay mounted to preserve per-tab state, and it provides useTabs().
  • Drawer — a minimal off-canvas drawer navigator with a sidebar and default slot; provides useDrawer().
  • NavigationRoot — the root of a navigator subtree; creates and provides a fresh navigator state from routes (isolated per root).
  • Screen — declarative per-screen options and slot fills, plus its Screen.Header / Screen.HeaderLeft / Screen.HeaderRight / Screen.TabBarItem sub-components.
  • Header — the headless default navigator header chrome (back button, title, header slots), switching content reactively.
  • TabBar — the headless default chrome for Tabs; unstyled buttons with accessibility wiring, overridable via renderTab.
  • Link — declarative navigation, the JSX flavor of nav.push, with the same per-route conditional typing.

Their prop types and related APIs remain documented below.

Constants#

TypeScript
const NAV_SNAPSHOT_VERSION = 1

The current nav snapshot schema version (value 1). Stored in NavSnapshot.version; bump it to reject old snapshots (onRestoreError fires 'version').

Types#

TypeScript
interface Nav {
    push<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>, options?: PushOptions): void;
    push<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>, options?: PushOptions): void;
    replace<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>, options?: PushOptions): void;
    replace<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>, options?: PushOptions): void;
    pop(count?: number, options?: PopOptions): void;
    popTo<K extends RouteId>(name: K): void;
    popToRoot(): void;
    reset(state: { stack: ReadonlyArray<StackEntry> }): void;
    dismiss(): void;
    readonly current: StackEntry;
    readonly stack: ReadonlyArray<StackEntry>;
    readonly canGoBack: boolean;
    readonly parent: Nav | null;
    readonly isLocallyFocused: boolean;
    readonly transition: TransitionState | null;
}

The navigator handle returned by useNav. Read getters are reactive; mutators commit immediately. push / replace are overloaded per route by whether params are required.

Register#

TypeScript
interface Register {} // empty — users augment it

Augment this via declare module '@sigx/lynx-navigation' with routes: typeof routes to register your route map. This drives all global type inference.

RegisteredRoutes#

TypeScript
type RegisteredRoutes = Register extends { routes: infer R } ? R : RouteMap;

Your registered route map, or the permissive RouteMap fallback when Register is not augmented.

RouteId#

TypeScript
type RouteId = keyof RegisteredRoutes & string;

The union of registered route names.

RouteParams#

TypeScript
type RouteParams<K extends RouteId> = ParamsOf<RegisteredRoutes[K]>;

The inferred params type for route K.

RouteSearch#

TypeScript
type RouteSearch<K extends RouteId> = SearchOf<RegisteredRoutes[K]>;

The inferred search type for route K.

RoutesWithParams#

TypeScript
type RoutesWithParams = { [K in RouteId]: RouteRequiresParams<RegisteredRoutes[K]> extends true ? K : never }[RouteId];

The union of route names that declare a params schema.

RoutesWithoutParams#

TypeScript
type RoutesWithoutParams = Exclude<RouteId, RoutesWithParams>;

The union of route names with no params schema.

RouteDefinition#

TypeScript
interface RouteDefinition<
    Params extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined,
    Search extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined,
> {
    component: ComponentLike;
    fallback?: ComponentLike | (() => unknown);
    params?: Params;
    search?: Search;
    path?: string;
    presentation?: Presentation;
    children?: Record<string, RouteDefinition>;
}

A single route entry. params / search are Standard Schema validators; path enables deep links; presentation defaults to 'card'.

RouteMap#

TypeScript
type RouteMap = Record<string, RouteDefinition>;

A map of route names to definitions.

ComponentLike#

TypeScript
type ComponentLike = ((...args: any[]) => unknown) | (() => Promise<{ default: (...args: any[]) => unknown }>);

A route component — a function component or a dynamic import (for lazy routes).

Presentation#

TypeScript
type Presentation = 'card' | 'modal' | 'fullScreen' | 'transparent-modal' | 'sheet';

How a screen is presented. card stays in its stack; the others escalate to root from nested stacks. sheet is a partial-height bottom sheet with a dimmed backdrop.

StackEntry#

TypeScript
interface StackEntry<R extends string = string, P = unknown, S = unknown> {
    readonly key: string;
    readonly route: R;
    readonly params: P;
    readonly search: S;
    state: unknown;          // user state, survives suspend/restore
    readonly presentation: Presentation;
}

One entry in a navigator stack.

PushOptions#

TypeScript
interface PushOptions { presentation?: Presentation; state?: unknown; animated?: boolean; }

Per-push overrides (override the route's presentation, seed entry state, or disable animation for one push).

PopOptions#

TypeScript
interface PopOptions { animated?: boolean; }

Per-pop options.

ScreenOptions#

TypeScript
interface ScreenOptions {
    title?: string | (() => string);
    headerShown?: boolean;          // default true
    gestureEnabled?: boolean;       // default true
    detents?: DetentSpec[];         // sheet: rest heights (fraction / px / keyboard); default [{ fraction: 0.5 }]
    initialDetentIndex?: number;    // default: last (most open)
    dragMode?: 'handle' | 'surface' | 'grabber';  // sheet: what owns the drag; renamed from dragHandle
    backdropDismiss?: boolean;      // default true
}

Per-screen options, settable via <Screen> or useScreenOptions. The detents / initialDetentIndex / backdropDismiss fields apply to sheet presentations. They use the DetentSpec geometry from @sigx/lynx-sheet — the route sheet now shares that engine, and the detents are tracked live. Renamed in 0.19 from snapPoints / initialSnapIndex (which took plain fraction numbers).

ScreenSlotFills#

TypeScript
interface ScreenSlotFills {
    header?: () => unknown;
    headerLeft?: () => unknown;
    headerRight?: () => unknown;
    tabBarItem?: (ctx: { active: boolean }) => unknown;
}

The slot fills a screen can register (written by the Screen.* sub-components).

ScreenChrome#

TypeScript
interface ScreenChrome {
    readonly title: string;
    readonly headerShown: boolean;
    readonly canGoBack: boolean;
    pop(): void;
    readonly header: ScreenSlotFills['header'] | undefined;
    readonly headerLeft: ScreenSlotFills['headerLeft'] | undefined;
    readonly headerRight: ScreenSlotFills['headerRight'] | undefined;
}

The reactive header data returned by useScreenChrome. Every property is a getter.

Href#

TypeScript
interface Href<K extends RouteId = RouteId> {
    readonly route: K;
    readonly params: RouteParams<K>;
    readonly search: RouteSearch<K>;
    readonly url: string | null;   // null when the route has no path
}

A typed, validated navigation target produced by hrefFor / parseHref.

CompiledPath#

TypeScript
interface CompiledPath {
    readonly source: string;
    readonly paramNames: readonly string[];
    readonly regex: RegExp;
    format(params: Record<string, string | number>): string;
}

The result of compilePath — a regex matcher plus a format() that fills the template.

TypeScript
interface NavSnapshot { version: number; stack: StackEntry[]; }

A persisted navigator snapshot (version plus stack).

TypeScript
interface NavStorageAdapter {
    load(): Promise<NavSnapshot | null> | NavSnapshot | null;
    save(snapshot: NavSnapshot): Promise<void> | void;
}

The storage backend for useNavSerializer. Implement load / save over any store (e.g. @sigx/lynx-storage).

UseNavSerializerOptions#

TypeScript
interface UseNavSerializerOptions {
    storage: NavStorageAdapter;
    debounceMs?: number;            // default 250
    onRestored?: (snapshot: NavSnapshot) => void;
    onRestoreError?: (reason: 'version' | 'shape' | 'unknown-route' | 'load-threw', err?: unknown) => void;
}

Options for useNavSerializer.

UseLinkingNavOptions#

TypeScript
interface UseLinkingNavOptions {
    prefixes?: string[];
    onURL?: (url: string, nav: Nav) => void;
    onUnmatched?: (url: string) => void;
    replaceInitial?: boolean;       // default true
}

Options for useLinkingNav.

TabInfo#

TypeScript
interface TabInfo {
    readonly name: string;
    readonly icon?: IconSpec | JSXElement;
    readonly label?: string;
    readonly accessibilityLabel?: string;
}

Metadata for a single tab (from each Tabs.Screen).

TabsNav#

TypeScript
interface TabsNav {
    readonly active: string;
    setActive(name: string): void;
    readonly tabs: ReadonlyArray<TabInfo>;
}

The handle returned by useTabs.

TabRenderContext#

TypeScript
interface TabRenderContext { readonly active: boolean; onPress(): void; }

The render context passed to TabBar's renderTab for each item.

DrawerNav#

TypeScript
interface DrawerNav { readonly isOpen: boolean; open(): void; close(): void; toggle(): void; }

The handle returned by useDrawer.

LinkProps#

TypeScript
type LinkProps = LinkPropsByRoute & { replace?: boolean; children?: unknown };
// LinkPropsByRoute = {
//   [K in RouteId]: K extends RoutesWithParams
//     ? { to: K; params: RouteParams<K>; search?: RouteSearch<K> }
//     : { to: K; params?: undefined; search?: RouteSearch<K> }
// }[RouteId]

The props of <Link>params is required exactly when the route declares a params schema.

TransitionState#

TypeScript
interface TransitionState {
    readonly kind: TransitionKind;
    readonly topEntry: StackEntry;
    readonly underneathEntry: StackEntry;
    readonly progress: unknown;   // SharedValue<number>, typed loosely
}

The in-flight transition exposed by nav.transition (null when idle).

TransitionKind#

TypeScript
type TransitionKind = 'push' | 'pop';

The direction of a transition.

TransitionRole#

TypeScript
type TransitionRole = 'top' | 'underneath';

A screen's role during a transition.

StandardSchemaV1#

TypeScript
interface StandardSchemaV1<Input = unknown, Output = Input> {
    readonly '~standard': {
        readonly version: 1;
        readonly vendor: string;
        readonly types?: { readonly input: Input; readonly output: Output };
    };
}

The Standard Schema interface used for params / search validators (zod, valibot, arktype all implement it).

InferOutput#

TypeScript
type InferOutput<S> = S extends StandardSchemaV1<unknown, infer O> ? O : unknown;

Extracts the output type of a Standard Schema.

EmptyParams#

TypeScript
type EmptyParams = Record<string, never>;

The params / search type for routes that declare no schema.

ParamsOf#

TypeScript
type ParamsOf<R> = R extends { params: infer S } ? InferOutput<S> : EmptyParams;

Infers a route definition's params type.

SearchOf#

TypeScript
type SearchOf<R> = R extends { search: infer S } ? InferOutput<S> : EmptyParams;

Infers a route definition's search type.

RouteRequiresParams#

TypeScript
type RouteRequiresParams<R> = R extends { params: object } ? true : false;

Whether a route definition declares a params schema.

See also#

  • Usage — practical guides and complete examples.
  • Overview — what Navigation is.