Skip to content

Latest commit

 

History

History
199 lines (157 loc) · 5.65 KB

README.md

File metadata and controls

199 lines (157 loc) · 5.65 KB

Build status Coverage status NPM version NPM bundle size (minified + gzip) Licence

@maxmilton/solid-router

A lightweight History API based router for Solid with the features you expect.

Features:

  • SPA routing using browser History API
  • Simple — single top level router, no nesting, no context, handles all <a> clicks
  • Light — few dependencies; under the hood it's mostly an abstraction on top of Solid's built-in Switch and Match components + a little handling logic
  • Flexible path matching — static paths, parameters, optional parameters, wildcards, and no match fallback
  • Optional URL search query params parsing

Note: This package is not designed to work with SSR or DOM-less pre-rendering. If you need a universal solution use solid-app-router instead.

Installation

npm install @maxmilton/solid-router

or

yarn add @maxmilton/solid-router

Usage

Simple + JavaScript

import { NavLink, Router, routeTo } from '@maxmilton/solid-router';
import { lazy } from 'solid-js';
import { render, Suspense } from 'solid-js/web';

const routes = [
  {
    path: '/example',
    component: lazy(() => import('./pages/example')),
  },
  {
    path: '/example/:id',
    component: lazy(() => import('./pages/example/[id]')),
  },
  {
    path: '/',
    component: lazy(() => import('./pages/home')),
  },
];

const App = () => (
  <>
    <div>
      <NavLink href="/">Home</NavLink>
      <NavLink href="/example" deepMatch>
        Examples
      </NavLink>
    </div>

    <Suspense fallback={'Loading...'}>
      <Router routes={routes} fallback={'Page Not Found'} />
    </Suspense>
  </>
);

render(App, document.body);

All features + TypeScript

import {
  NavLink,
  Router,
  useURLParams,
  routeTo,
  type Route,
} from '@maxmilton/solid-router';
import { lazy, type Component, type JSX } from 'solid-js';
import { ErrorBoundary, render, Suspense } from 'solid-js/web';

interface ErrorPageProps {
  code?: number;
  message?: string;
}

const ErrorPage: Component<ErrorPageProps> = ({ error }) => (
  <div>
    <h1>{error.code} Error</h1>
    <p>{error.message || 'An unknown error occurred'}</p>
  </div>
);

const Loading: Component = () => <p>Loading...</p>;

const Nav: Component = () => (
  <nav>
    <NavLink href="/">Home</NavLink>
    <NavLink href="/example" deepMatch>
      Examples
    </NavLink>
    <NavLink href="/redirect">Redirect</NavLink>
    <NavLink href="/xx/123/abc?a=1&a=2&b=yy&c">XX</NavLink>
  </nav>
);

const routes: Route[] = [
  {
    path: '/xx/:x1/:x2?',
    component: (props) => {
      console.log(props.params); // -> { x1: "...", x2: ... }

      const [urlParams, setUrlParams] = useURLParams();
      console.log(urlParams()); // -> { ... }

      // Add new URL params
      setUrlParams({ ...urlParams(), name: 'example', x: [1, 2] }); // -> location.search == "?name=example&x=1&x=2"

      // Delete URL params (set to `undefined`)
      setUrlParams({ ...urlParams(), x: undefined }); // -> location.search == "?name=example"

      // Regular links are still handled by the router
      return <a href="/">I'm still handled correctly!</a>;
    },
  },
  {
    path: '/example',
    component: lazy(() => import('./pages/example')),
  },
  {
    path: '/example/:id',
    component: lazy(() => import('./pages/example/[id]')),
  },
  {
    path: '/redirect',
    component: () => routeTo('/example', true) as JSX.Element,
  },
  {
    path: '/',
    component: lazy(() => import('./pages/home')),
  },
];

const App = (): JSX.Element => (
  <>
    <Nav />
    <ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
      <Suspense fallback={<Loading />}>
        <Router
          routes={routes}
          fallback={() => {
            const error = new Error('Not found');
            error.code = 404;
            throw error;
          }}
          // Scroll to top on route change
          onRouted={() => window.scrollTo(0, 0)}
          onError={(error) => console.error(error)}
        />
      </Suspense>
    </ErrorBoundary>
  </>
);

render(App, document.body);

API

TODO: Write me

Browser support

No particularly modern JavaScript APIs are used so browser support should be excellent. However, keep in mind Solid's official browser support only targets modern evergreen browsers.

Bugs

Report any bugs you encounter on the GitHub issue tracker.

Changelog

See releases on GitHub.

License

MIT license. See LICENSE.


© 2024 Max Milton