Skip to content

Route states

What a page shows instead of itself: RouteErrorState reads the failure’s kind (offline, session ended, no access, not found, the server’s) and offers the ways out it allows; NotFoundState and NoAccessState name two of them; AppLoadingState is the screen while the app starts. RouterErrorState and RouterNotFoundState, from the router entry, plug them into TanStack Router.

Language
Appearance

The server failed

A retry where retrying can help, and the way to the start.

You’re offline

Check your internet connection, then try again.

import { useState } from 'react';
import { RouteErrorState } from '@arbol-ai/ui';

const RetryExample = () => {
  const [isRetrying, setIsRetrying] = useState(false);
  return (
    <RouteErrorState
      className="min-h-0"
      error={{ status: 503 }}
      homeHref="#/route-states"
      isRetrying={isRetrying}
      onRetry={() => {
        setIsRetrying(true);
        setTimeout(() => {
          setIsRetrying(false);
        }, 1500);
      }}
    />
  );
};

<RetryExample />

The session ended

You’re offline

Check your internet connection, then try again.

import { RouteErrorState } from '@arbol-ai/ui';

<RouteErrorState
  className="min-h-0"
  error={{ status: 401 }}
  homeHref="#/route-states"
  onSignIn={() => undefined}
/>

Not found

Page not found

It doesn’t exist, it moved, or it belongs to another organization.

import { NotFoundState } from '@arbol-ai/ui';

<NotFoundState className="min-h-0" homeHref="#/route-states" />

No access

The app decides who may see the page; the state says so, and who to ask.

You don’t have access to this page

It’s for whoever manages the agenda (the Administration role). Your role is Front desk.

import { NoAccessState } from '@arbol-ai/ui';

<NoAccessState
  className="min-h-0"
  description="It’s for whoever manages the agenda (the Administration role). Your role is Front desk."
  homeHref="#/route-states"
  homeLabel="Go to the agenda"
/>

Offline

You’re offline

Check your internet connection, then try again.

import { RouteErrorState } from '@arbol-ai/ui';

<RouteErrorState className="min-h-0" kind="offline" onRetry={() => undefined} />

The app starting

Signing you in…
import { AppLoadingState } from '@arbol-ai/ui';

<div className="rounded-card overflow-hidden border">
  <AppLoadingState className="min-h-64" label="Signing you in…" />
</div>

With TanStack Router

The report fails on its first load; Try again loads it again. A path no route matches shows the not-found state. Each example runs its own router in memory.

import { Outlet, RouterProvider, createMemoryHistory, createRootRoute, createRoute, createRouter } from '@tanstack/react-router';
import { useMemo } from 'react';
import { useLocale } from 'react-aria-components';
import { Link } from '@arbol-ai/ui';
import { RouterErrorState, RouterNotFoundState, RouterUIProvider } from '@arbol-ai/ui/router';

const createExampleRouter = () => {
  let attempts = 0;
  const rootRoute = createRootRoute({ component: ExampleRoot });
  const reportRoute = createRoute({
    component: () => <p className="text-sm">18 appointments today, 3 conversations waiting.</p>,
    getParentRoute: () => rootRoute,
    loader: () => {
      attempts += 1;
      if (attempts === 1) {
        throw Object.assign(new Error('Service unavailable'), { status: 503 });
      }
    },
    path: '/',
  });
  return createRouter({
    defaultErrorComponent: (props) => <RouterErrorState {...props} className="min-h-0" />,
    defaultNotFoundComponent: () => <RouterNotFoundState className="min-h-0" homeHref="/" />,
    history: createMemoryHistory({ initialEntries: ['/'] }),
    routeTree: rootRoute.addChildren([reportRoute]),
  });
};

const RouterExample = () => {
  const router = useMemo(() => createExampleRouter(), []);
  return <RouterProvider router={router} />;
};

const ExampleRoot = () => {
  const { locale } = useLocale();
  return (
    <RouterUIProvider locale={locale}>
      <div className="rounded-card grid gap-4 border p-4">
        <nav aria-label="Example sections" className="flex gap-4 text-sm">
          <Link href="/">Report</Link>
          <Link href="/archive">Archive (no such page)</Link>
        </nav>
        <Outlet />
      </div>
    </RouterUIProvider>
  );
};

<RouterExample />

Source

The examples above are src/blocks/route-states/route-states.examples.tsx, which the library’s tests render too.

Type to search…

↑↓ navigate↵ selectEsc close