# Hooks and slots (https://docs.salla.dev/twilight/react/guide/hooks-and-slots)



Read this when you need store data inside a component, or want to add content to an engine page without replacing it.

Two different things share the word "hook" here, so keep them apart.

* **React hooks** (`useStore`, `useTheme`, …) are functions a component calls to read data. Any function whose name starts with `use` is a React hook.
* **Hook slots** are named spots in the engine's pages where you can inject content without replacing the page.

## Engine hooks [#engine-hooks]

Each engine hook has its own import path, so you only bundle what you use. The most common:

| Hook          | Gives you                                                 |
| ------------- | --------------------------------------------------------- |
| `useStore`    | The store: name, settings, and a `refresh()`              |
| `useTheme`    | `color`, `font`, `settings` and `isRTL`                   |
| `useMoney`    | `format(amount)` for prices                               |
| `useProduct`  | A product whose price and stock follow the chosen options |
| `useWishlist` | `has`, `add`, `remove`, `toggle`, `ids`, `loading`        |
| `useUser`     | The signed-in customer                                    |
| `useAsyncFn`  | Wrap an async action with a `loading` flag                |

```tsx title="app/components/product/ProductCard.tsx"
import { useWishlist } from '@salla.sa/twilight-theme-engine/hooks/useWishlist';

function WishlistButton({ productId }: { productId: number }) {
  const wishlist = useWishlist();
  return <button onClick={() => wishlist.toggle(productId)}>♥</button>;
}
```

Each hook has a page in the Hooks tab: [useStore](https://docs.salla.dev/twilight/react/hooks/use-store), [useTheme](https://docs.salla.dev/twilight/react/hooks/use-theme),
[useMoney](https://docs.salla.dev/twilight/react/hooks/use-money), [useProduct](https://docs.salla.dev/twilight/react/hooks/use-product),
[useWishlist](https://docs.salla.dev/twilight/react/hooks/use-wishlist) and [useAsyncFn](https://docs.salla.dev/twilight/react/hooks/use-async-fn).

Hooks only work inside a component, and only below `TwilightProvider`, which the root route already sets up.

## Hook slots [#hook-slots]

The engine puts a `HookSlot` at useful places in its pages. A slot renders whatever you registered under its name,
and nothing if you registered nothing. Some of the names (from the `HookName` enum):

| Area              | Names                                                                                              |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| Page              | `body:start`, `body:end`, `head:start`, `head:end`                                                 |
| Header and footer | `header:start`, `header:end`, `footer:start`, `footer:end`, `copyright`                            |
| Product           | `product:single.description.start`, `product:single.description`, `product:single.description.end` |
| Cart              | `cart:items.start`, `cart:items.end`, `cart:summary.start`, `cart:summary.end`                     |

A slot exists only where a page renders it. The header and footer slots live inside the engine's own header and footer,
so if your layout or a forked page replaces them, render the slot there yourself.

### Register content in a slot [#register-content-in-a-slot]

`hookRegistry.register(name, handler, priority)` adds a handler. The handler receives a context and returns markup,
or `null` to show nothing. Higher priority runs first, and the default is 50. The starter theme does this once at startup:

```tsx title="app/hooks/index.tsx"
import { hookRegistry, HookName, type HookContext } from '@salla.sa/twilight-theme-engine/hooks';

hookRegistry.register(
  HookName.BODY_END,
  (context: HookContext) => {
    const { twilight } = context;
    if (twilight?.theme?.settings?.enable_add_product_toast === false) return null;
    return <AddProductToast />;
  },
  50
);
```

The context always has `twilight` (store, theme, currency and more). Some slots add more: the product description slot
also passes `product`.

Call your registration function from `app/router.tsx` so it runs on both the server and the browser.
The [slot recipe](https://docs.salla.dev/twilight/react/recipes/add-content-to-a-slot) walks through it.

### Register from a component [#register-from-a-component]

`useHook(name, handler, priority)` registers while a component is mounted:

```tsx
import { useHook } from '@salla.sa/twilight-theme-engine/hooks';

function PromoRegistration() {
  useHook('header:start', () => <PromoBar />);
  return null;
}
```

When the component unmounts, `useHook` removes only the handler it registered. For something the whole theme needs, register once at startup with `hookRegistry.register`.

### Add a slot to your own page [#add-a-slot-to-your-own-page]

Put a `HookSlot` where you want others (or later you) to inject content. `fallback` shows when nothing is registered:

```tsx
import { HookSlot } from '@salla.sa/twilight-theme-engine/hooks';

function FaqPage({ page }: { page: { id: string } }) {
  return (
    <>
      <h1>FAQ</h1>
      <HookSlot name="my-page:after-title" context={{ page }} fallback={null} />
    </>
  );
}
```

See [HookSlot](https://docs.salla.dev/twilight/react/hooks/hook-slot) and [useHook](https://docs.salla.dev/twilight/react/hooks/use-hook) for every prop.

**Next:** [Styling](https://docs.salla.dev/twilight/react/guide/styling), to give your theme its look.
