Home and catalog slots
Where the home page, product list, brands page and not-found page expose slots, and what each one receives.
Use these slots when you want a banner, promo strip or widget on the home page, above or below a product listing, around the brands index, or on the 404 page, without forking the route. New to slots? Read Slots and Page frame slots first.
None of the slots on this page pass a context of their own. Your handler receives only twilight (store, theme, currency and more).
Home page
Route: Home.
home:starthome:contenthome:end| Slot | Position | Context | Notes |
|---|---|---|---|
home:start | First thing in the page, before every home block. | none | Good for a top announcement strip. |
home:content | Directly after home:start, still before the first block. | none | Sits next to home:start, so the two render back to back. Use it for a second, independent injection point. |
home:end | After the last home block. | none | The slots render even when the page has no blocks. |
Blocks are not slots
Home blocks (sliders, banners, product lists) come from the theme's twilight.json catalog and the store's page builder, not from slots. To change a block, see Add a home block. There is no slot between two blocks.
Product list pages
The same page component renders every product listing: category, brand, tag, search and the products lists (latest, best sellers, offers, order again). A handler registered once shows on all of them.
product:list.startproduct:list.items.startProduct grid
product:list.items.endproduct:list.end| Slot | Position | Context | Notes |
|---|---|---|---|
product:list.start | After the breadcrumb (and after the brand banner and header on a brand page), before the filters and the grid. Full width. | none | Best place for a promo strip above the whole listing. |
product:list.items.start | In the main column, after the page title and the sort and filter controls, immediately before the product grid. | none | Narrower than product:list.start: it sits beside the filter sidebar, not above it. |
product:list.items.end | In the main column, immediately after the product grid. | none | Directly under the grid. |
product:list.end | Last item in the page container, after the mobile filters drawer and the category testimonials block. | none | Full width, at the bottom of the listing. |
The slots render on every listing, including ones with no filters and ones with no products. The context does not say which listing you are on. To show something only on some listings, read the current route in your handler, for example with TanStack Router's useLocation.
Example: promo strip above a listing
import { hookRegistry } from '@salla.sa/twilight-theme-engine/hooks';
export function registerThemeHooks() {
hookRegistry.register(
'product:list.start',
() => (
<div className="mb-6 rounded-md bg-primary p-3 text-center text-sm font-bold text-primary-reverse">
Free delivery on orders over 200 SAR
</div>
),
50
);
}Call registerThemeHooks() once at module scope, as in Add content to a slot.
Brands page
Route: Brands. Both slots sit inside the alphabetical list, so they render only when the store has at least one brand. With no brands the page shows an empty state and neither slot renders.
brands:index.items.startonly with brandsSection A and B: brand cards
brands:index.items.endonly with brands| Slot | Position | Context | Notes |
|---|---|---|---|
brands:index.items.start | After the letter navigation, before the first letter section. | none | Skipped when the store has no brands. |
brands:index.items.end | After the last letter section. | none | Skipped when the store has no brands. |
The brands index does not render the product:list.* slots. A single brand's page (with its products) does.
Not-found page
Route: Not found. The three slots render inside the error page, between the message and the "Back to Home" link. While a short link is still being resolved the page renders nothing, so no slot appears.
notfound:startnotfound:contentnotfound:end| Slot | Position | Context | Notes |
|---|---|---|---|
notfound:start | Directly under the message text. | none | All three slots render back to back, so ordering between them is the only difference. |
notfound:content | After notfound:start. | none | Good for a search box or a list of popular categories. |
notfound:end | After notfound:content, before the home link. | none | Appears above the "Back to Home" button. |
Example: help links on the 404 page
import { useHook } from '@salla.sa/twilight-theme-engine/hooks/useHook';
export function NotFoundHelp() {
useHook('notfound:content', () => (
<p className="mb-6 text-gray-500">
Looking for something? Try the <a href="/search">search page</a> or{' '}
<a href="/contact-us">contact us</a>.
</p>
));
return null;
}Render <NotFoundHelp /> once under your layout so the handler stays registered for the whole visit.