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.

/
Header
home:start
home:content
Block 1: slider, banners and so on
Block 2
Block N
home:end
Footer
Slot: add your content hereDrawn by the engine
Home page
SlotPositionContextNotes
home:startFirst thing in the page, before every home block.noneGood for a top announcement strip.
home:contentDirectly after home:start, still before the first block.noneSits next to home:start, so the two render back to back. Use it for a second, independent injection point.
home:endAfter the last home block.noneThe 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.

/category-name/c123
Header
Breadcrumb, and the brand banner on brand pages
product:list.start
Filterswhen the page has filters
Title, sort and filter controls
product:list.items.start

Product grid

product:list.items.end
Category testimonialscategory pages, when enabled
product:list.end
Footer
Slot: add your content hereDrawn by the engine
Product list page
SlotPositionContextNotes
product:list.startAfter the breadcrumb (and after the brand banner and header on a brand page), before the filters and the grid. Full width.noneBest place for a promo strip above the whole listing.
product:list.items.startIn the main column, after the page title and the sort and filter controls, immediately before the product grid.noneNarrower than product:list.start: it sits beside the filter sidebar, not above it.
product:list.items.endIn the main column, immediately after the product grid.noneDirectly under the grid.
product:list.endLast item in the page container, after the mobile filters drawer and the category testimonials block.noneFull 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

app/hooks/index.tsx
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
Header
Breadcrumb and page title
Letter navigation: A B C D ...
brands:index.items.startonly with brands

Section A and B: brand cards

brands:index.items.endonly with brands
Footer
Slot: add your content hereDrawn by the engine
Brands page
SlotPositionContextNotes
brands:index.items.startAfter the letter navigation, before the first letter section.noneSkipped when the store has no brands.
brands:index.items.endAfter the last letter section.noneSkipped 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.

/no-such-page
Header
404, title and message
notfound:start
notfound:content
notfound:end
Back to Home button
Footer
Slot: add your content hereDrawn by the engine
Not-found page
SlotPositionContextNotes
notfound:startDirectly under the message text.noneAll three slots render back to back, so ordering between them is the only difference.
notfound:contentAfter notfound:start.noneGood for a search box or a list of popular categories.
notfound:endAfter notfound:content, before the home link.noneAppears above the "Back to Home" button.
app/components/NotFoundHelp.tsx
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.

Next

On this page