# Layout and components (https://docs.salla.dev/twilight/react/guide/layout-and-components)



Read this when you want to change how the header, footer, product card or home page look.

A **component** is a function that returns markup. The engine ships many (header, footer, product card, home blocks),
and your theme can replace the ones you want to change. The sections below go from the biggest swap to the smallest.

## The layout wraps every page [#the-layout-wraps-every-page]

The **layout** is the frame around each route: header on top, footer at the bottom, your page in between.
By default the engine uses its `MasterLayout`. You can pass your own to `TwilightProvider` in the root route:

```tsx title="app/routes/__root.tsx"
import { TwilightProvider } from '@salla.sa/twilight-theme-engine';
import themeTranslations from 'virtual:twilight/theme-translations';
import { ThemeLayout } from '../components/layout/ThemeLayout';

// inside RootComponent
<TwilightProvider translations={themeTranslations} layout={ThemeLayout}>
  <Outlet />
</TwilightProvider>
```

A layout is a component that receives `children` (the current page). This is the starter theme's, shortened:

```tsx title="app/components/layout/ThemeLayout.tsx"
import { Suspense, type ReactNode } from 'react';
import { Footer } from '@salla.sa/twilight-theme-engine/layout';
import { Header } from './Header';

export function ThemeLayout({ children }: { children: ReactNode }) {
  return (
    <>
      <div className="app-inner flex flex-col min-h-full">
        <Header />
        <main id="main-content" className="flex-1">
          {children}
        </main>
        <Suspense fallback={null}>
          <Footer />
        </Suspense>
      </div>
      {/* global modals: offer, login, scopes … */}
    </>
  );
}
```

It mirrors the engine's layout: its own header, the engine's footer, and the same global modals. Start from a copy of the engine's layout and change only what you need. The engine's `Footer` has two looks, picked by the theme setting `footer_layout` (see [Header and footer](https://docs.salla.dev/twilight/react/layouts/header-and-footer#the-footer)).
See the [MasterLayout reference](https://docs.salla.dev/twilight/react/layouts/master-layout).

<Callout>
  Only the layout swaps the header and footer. To just add a banner above the header, use a
  [hook slot](https://docs.salla.dev/twilight/react/guide/hooks-and-slots) instead of replacing everything.
</Callout>

## Swap the product card with the registry [#swap-the-product-card-with-the-registry]

The **component registry** is a name-to-component map. The engine looks a few names up at render time,
so registering your component under that name replaces the built-in one everywhere.

The product card is the main one (`product:card`). It needs both calls:

```tsx title="app/router.tsx (your theme)"
import { registry } from '@salla.sa/twilight-theme-engine';

registry.register('product:card', MyProductCard); // seeds an "original"
registry.override('product:card', MyProductCard); // now it counts as an override
```

The engine card only uses your component when `register` has run first and `override` after it, so `override` alone does nothing.
Step by step: [Replace the product card](https://docs.salla.dev/twilight/react/recipes/replace-the-product-card).

The engine looks up only these names: `product:card`, `product:gallery`, `product:list-page` and `product:list-skeleton`
(every product listing page and its loading skeleton), `account:layout-pending` (the skeleton shown while
account pages load), and the `home:*` names. Anything else is not swappable this way.

## Swap a home block [#swap-a-home-block]

The home page is built from blocks that a merchant arranges. Each block has a key, and `registerHomeComponents`
binds keys to components. The starter theme starts from the engine defaults and replaces some:

```tsx title="app/router.tsx"
import {
  registerHomeComponents,
  DefaultHomeComponents,
} from '@salla.sa/twilight-theme-engine/routes/home';

registerHomeComponents({
  ...DefaultHomeComponents,
  brands: Brands,
  'products-slider': ProductsSlider,
});
```

Keep `...DefaultHomeComponents` first, so blocks you did not replace still render. To add a brand new block,
see [Add a home block](https://docs.salla.dev/twilight/react/recipes/add-a-home-block).

## Or just wrap the engine component [#or-just-wrap-the-engine-component]

You do not have to rebuild a component. The starter theme's `ProductCard` imports the engine card
(`import { ProductCard as EngineProductCard } from '@salla.sa/twilight-theme-engine/product'`) and renders it
with small changes. Wrapping keeps engine fixes flowing in.

## Which to choose [#which-to-choose]

| Goal                    | Use                                          |
| ----------------------- | -------------------------------------------- |
| New header or footer    | Your own `layout`                            |
| Different product card  | Registry `product:card`                      |
| Different home block    | `registerHomeComponents`                     |
| Add content in one spot | A [hook slot](https://docs.salla.dev/twilight/react/guide/hooks-and-slots)        |
| Change a whole page     | [Replace the route](https://docs.salla.dev/twilight/react/guide/routes-and-pages) |

Every engine component is documented in the Components tab, starting with [MasterLayout](https://docs.salla.dev/twilight/react/layouts/master-layout).

**Next:** [Hooks and slots](https://docs.salla.dev/twilight/react/guide/hooks-and-slots), to add content without replacing anything.
