# Routes and pages (https://docs.salla.dev/twilight/react/guide/routes-and-pages)



<Callout title="Framework: TanStack Start">
  This page is written for TanStack Start, the default and currently supported framework. [See what depends on the framework](https://docs.salla.dev/twilight/react/start/frameworks).
</Callout>

Read this when you want a page the engine does not have, or want to change one it does.

A **route** connects a URL to a page. The engine ships a route for every storefront page
(home, product, category, cart, blog, account and more), so a new theme already has all of them.
You only write route files for pages you add or take over.

## Where routes live [#where-routes-live]

Two things work together in your theme:

* `app/routes.ts` is the **manifest**. It lists the pages you add or replace.
* `app/routes/` holds the **route files** those entries point to.

At build time the engine plugin merges your manifest with its built-in routes and writes
`app/routeTree.gen.ts`. Most files in `app/routes/` are generated copies of the engine's routes,
marked with a `// @auto-generated` first line. Of those, only `__root.tsx` is meant to be edited by hand.
Some built-in routes add no file there at all: every product list (search, categories, tags, brands,
`/products?source=…`), the product reviews page and the redirects from old Twig addresses are served
from the engine's own `.twilight/` folder.

<Callout type="warn">
  Never put `// @auto-generated` at the top of a route file you wrote. That marker tells the
  plugin the file is disposable, and the next build overwrites it.
</Callout>

## Every URL starts with the locale [#every-url-starts-with-the-locale]

Every storefront route path begins with `{-$locale}`. It is an optional URL segment that holds
the language, so one route serves `/ar/cart` and `/en/cart`. [Languages and RTL](https://docs.salla.dev/twilight/react/guide/languages-and-rtl)
explains what the engine does with it.

## Add a page [#add-a-page]

Add an entry to the manifest. The second argument is a file name inside `app/routes/`.

```ts title="app/routes.ts"
import { route } from '@tanstack/virtual-file-routes';

export const routes = [route('/faq', 'faq.tsx')];
```

Create that file. Keep the `{-$locale}` prefix in the path.

```tsx title="app/routes/faq.tsx"
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/{-$locale}/faq')({
  component: () => <div>FAQ</div>,
});
```

Your page is now served at `/ar/faq` and `/en/faq`. If it returns a 404, restart the dev server so the route tree is regenerated.
The [Add a page recipe](https://docs.salla.dev/twilight/react/recipes/add-a-page) has the full walkthrough.

## Replace a built-in page [#replace-a-built-in-page]

There are two ways, and both keep the engine's path:

* **Take the file over.** Delete the `// @auto-generated` line from the route's file in `app/routes/`. For a route the
  engine serves from `.twilight/`, add a file of the same name (for example `app/routes/search.tsx`) without that line.
  The build uses your file instead of the engine's.
* **Point the path at another file** with a manifest entry, such as `route('/cart', 'cart-page.tsx')`. The theme entry
  **replaces** the engine's.

The Raed starter theme takes over three files this way: `app/routes/cart.tsx`, `$slug.p$id.tsx` (the product page) and
`$slug.page-$id.tsx` (a CMS page). Its manifest is empty. They reuse the engine's data and head, and swap only the
component. Here is the cart one, shortened:

```tsx title="app/routes/cart.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { Cart } from '@salla.sa/twilight-theme-engine/routes/cart';
import { CartSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
import { CartPage } from '../components/cart/CartPage';

export const Route = createFileRoute('/{-$locale}/cart')({
  loader: ({ params }) => Cart.loader({ locale: params.locale }),
  head: withHead(Cart),
  pendingComponent: () => <CartSkeleton />,
  component: CartComponent,
});

function CartComponent() {
  const data = Route.useLoaderData();
  return <CartPage {...data} />;
}
```

## The four parts of a route [#the-four-parts-of-a-route]

| Part               | What it does                                                               |
| ------------------ | -------------------------------------------------------------------------- |
| `loader`           | Fetches the page data on the server, and again on in-app navigation.       |
| `head`             | Sets the page title and meta tags. `withHead(Module)` reuses the engine's. |
| `pendingComponent` | A skeleton shown while the loader runs.                                    |
| `component`        | Reads `Route.useLoaderData()` and renders.                                 |

Each built-in page is a module with `loader`, `head` and `Component`, imported from
`@salla.sa/twilight-theme-engine/routes/<page>`. That is why a fork can keep the engine's loader and replace only the markup.

<Callout>
  Replacing a page means you now own it, including future engine fixes to it. If you only want to add something to the
  page, use a [slot](https://docs.salla.dev/twilight/react/guide/hooks-and-slots) instead. The [fork recipe](https://docs.salla.dev/twilight/react/recipes/fork-a-built-in-route) shows the safe way.
</Callout>

To restyle every product list, fork no route: register your page as `product:list-page`, as Raed does in
`app/router.tsx`. See [Replace the whole product list page](https://docs.salla.dev/twilight/react/recipes/replace-the-product-card#replace-the-whole-product-list-page).

All built-in routes are listed in the [Routes tab](https://docs.salla.dev/twilight/react/routes).

**Next:** [Loading data](https://docs.salla.dev/twilight/react/guide/loading-data), to fill your route with store data.
