Not-found page

The page shown when no route matches or a loader says the thing does not exist.

Framework: TanStack Start

This page is written for TanStack Start, the default and currently supported framework. See what depends on the framework.

When a customer opens a URL that leads nowhere, they see a large "404", a message, a back-home button and three hook slots. Customise it when you want your own wording, layout or links on the 404.

It has no URL of its own: the router shows it in place of whatever page was asked for.

When it renders

CauseResult
No route matches the URL (/no-such-page)The not-found page. A product short link is tried first.
A loader calls notFound()The not-found page. The category, brand and tag loaders do this.
A loader uses findOrThrow (product, custom page) and the API answers 404 or 410The not-found page: findOrThrow calls notFound() for you.

Change the text and content

The default page takes its text from your translations, so edit those first:

TextTranslation key
Titlecommon.errors.404
Messagecommon.errors.error_occurred
Home buttoncommon.elements.back_home

To add content without replacing the page, fill the notfound:start, notfound:content or notfound:end hook slots from your theme.

Replace the page

The engine's component is not a public export, and createRouter has no option to swap it. TanStack Router lets you define your own instead:

  • For one route. Add notFoundComponent to the route file of a page you have taken over.
  • For all routes. Set notFoundComponent on the root route in app/routes/__root.tsx. A notFound() thrown by a child route is handled by the nearest route that defines one.
app/routes/brands.$id.tsx
import { createFileRoute, Link } from '@tanstack/react-router';
import {
  ProductListing,
  type ProductListLoaderData,
} from '@salla.sa/twilight-theme-engine/routes/product-listing';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';

export const Route = createFileRoute('/{-$locale}/brands/$id')({
  loader: ({ params }): Promise<ProductListLoaderData> =>
    ProductListing.loader({ params: { source: 'brands', id: params.id }, locale: params.locale }),
  head: withHead(ProductListing),
  component: () => <ProductListing.Component {...Route.useLoaderData()} />,
  // Shown when the brand does not exist (the loader calls notFound())
  notFoundComponent: () => (
    <div className="container py-16 text-center">
      <h1>This brand is gone</h1>
      <Link to="/brands">See all brands</Link>
    </div>
  ),
});

A findOrThrow that gets a 404 or 410 calls the same notFound(), so your notFoundComponent covers it too. To raise a not-found yourself, call notFound() from @salla.sa/twilight-theme-engine/providers in your loader. The exact notFoundComponent rules belong to TanStack Router, so check its documentation for your version.

Edge cases

  • Short links never flash a 404. While the lookup runs the page renders nothing.
  • Server errors are separate. Any other failed request in a loader shows the router's error page (400 or a generic error), not a 404.

See also

On this page