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
| Cause | Result |
|---|---|
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 410 | The 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:
| Text | Translation key |
|---|---|
| Title | common.errors.404 |
| Message | common.errors.error_occurred |
| Home button | common.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
notFoundComponentto the route file of a page you have taken over. - For all routes. Set
notFoundComponenton the root route inapp/routes/__root.tsx. AnotFound()thrown by a child route is handled by the nearest route that defines one.
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
- SEO redirects, for short links
- Product page, Category page and Brand page
- Overview and Routes and pages