solid-fuse

Navigation

Navigate between pages with push, pop, and replace

Fuse provides a Navigator component that manages a page stack, backed by Flutter's Navigator 2.0.

Basic setup

import { Navigator } from "solid-fuse";

function App() {
  return <Navigator initialPage={() => <HomePage />} />;
}

initialPage accepts either a JSX thunk (sugar for a default Material page) or a PageConfig built with materialPage({...}) when you want to customize the transition or page options.

useNavigation

Any component inside a Navigator can access the navigation API:

import { GestureDetector, Text, View, useNavigation } from "solid-fuse";

function HomePage() {
  const nav = useNavigation();

  return (
    <View flex={{ gap: 16 }} padding={24}>
      <Text fontSize={24}>Home</Text>
      <GestureDetector onTap={() => nav.push(() => <DetailPage />)}>
        <View padding={12} decoration={{ color: "blue", borderRadius: 8 }}>
          <Text color="white">Go to detail</Text>
        </View>
      </GestureDetector>
    </View>
  );
}

API

MethodDescription
nav.push(page)Push a page. page is a JSX thunk or a PageConfig. Returns a promise that resolves with the value passed to pop(result), or null if the page is removed any other way (back gesture, replaceAll, disposal).
nav.pop(result?)Pop the top page. Optional result resolves the pending push promise. No-op on a single-entry stack.
nav.pushReplacement(page, result?)Replace the top page. Pending promise of the replaced page resolves with result.
nav.popUntil(name?)Pop until the named route is on top, or to the root if no name given. No-op (with warning) if the name isn't on the stack.
nav.replaceAll(configs)Replace the entire stack with new pages. Returns a promise per new page.
nav.stackDepth()Reactive getter for the current stack depth.
nav.pages()Reactive getter for the page entry list.

Pages are configs, not JSX

A page in Fuse is a configuration object — { type, child, props } — not a JSX element you render directly. The built-in materialPage({...}) factory returns one of these configs for a Material-style transition.

import { Text, View, materialPage, useNavigation } from "solid-fuse";

function HomePage() {
  const nav = useNavigation();

  const openSettings = () =>
    nav.push(
      materialPage({
        name: "settings",
        fullscreenDialog: true,
        child: () => <SettingsPage />,
      }),
    );

  return (
    <View padding={24}>
      <Text>...</Text>
    </View>
  );
}

When you pass a plain thunk to nav.push(() => <X />), it's sugar for materialPage({ child: () => <X /> }).

materialPage props

PropTypeDefaultDescription
child() => JSX.ElementrequiredPage contents (thunk so it isn't built until the page is mounted)
namestringRoute name. Used by popUntil(name)
fullscreenDialogbooleanfalseSlides up instead of sideways, shows close button
maintainStatebooleantrueKeep state alive when not the top page

Back gestures

iOS swipe-back and Android back button are handled automatically. The Navigator's onDidRemovePage callback fires when the system removes a page (back gesture, declarative mid-stack removal) and resolves the corresponding push promise with null. You don't need to wire this up.

Full example

A two-page app with a list and detail view:

import { createSignal, For } from "solid-js";
import {
  GestureDetector,
  Navigator,
  Text,
  View,
  useNavigation,
} from "solid-fuse";

const items = ["Apples", "Bananas", "Cherries"];

function App() {
  return <Navigator initialPage={() => <ListPage />} />;
}

function ListPage() {
  const nav = useNavigation();

  return (
    <View flex={{ gap: 4 }}>
      <Text fontSize={24} fontWeight="bold" padding={{ bottom: 8 }}>
        Fruits
      </Text>
      <For each={items}>
        {(item) => (
          <GestureDetector onTap={() => nav.push(() => <DetailPage name={item} />)}>
            <View
              padding={16}
              decoration={{ border: { bottom: { width: 1, color: "#E0E0E0" } } }}
            >
              <Text fontSize={16}>{item}</Text>
            </View>
          </GestureDetector>
        )}
      </For>
    </View>
  );
}

function DetailPage(props: { name: string }) {
  const nav = useNavigation();

  return (
    <View flex={{ align: "center", justify: "center", expand: true }}>
      <Text fontSize={32}>{props.name}</Text>
      <GestureDetector onTap={() => nav.pop()}>
        <Text color="blue" fontSize={16}>Back to list</Text>
      </GestureDetector>
    </View>
  );
}

Returning a value from a page

nav.push returns a promise that resolves to whatever pop(result) is called with — or null if the page is removed any other way:

const selected = await nav.push<string>(() => <PickerPage />);
if (selected !== null) {
  // user picked something
}

Inside the picker:

function PickerPage() {
  const nav = useNavigation();
  return (
    <GestureDetector onTap={() => nav.pop("apple")}>
      <Text>Pick apple</Text>
    </GestureDetector>
  );
}

Custom page types

You can build custom page types with different transitions. See Creating Pages for how to build your own Material, Cupertino, or fade-transition factories.

On this page