Product page slots

Where the product page exposes slots around the details, add-to-cart form and related products, and what each one receives.

Use these slots when you want a badge, size-guide link, delivery note or promo around a product's details, under the add-to-cart form, or around the related-products slider, without forking the page. New to slots? Read Slots and Page frame slots first. The route itself is documented in Product.

Layout

/product-name/p123
Header
Breadcrumb
product:start
Gallery
product:details.start
Product details
product:single.description.startcontext: product
Brand, name, price, description and stock rows
product:single.descriptioncontext: product
Installment and metadata
product:details.end
product:single.form.start
Add-to-cart form
product:single.form.end
product:single.description.endcontext: product
Quick order
Offers and reviews
product:related.start

Related products slider

product:related.end
Testimonials
product:end
Footer
Slot: add your content hereDrawn by the engine
Product page

Slots

SlotPositionContextNotes
product:startAfter the breadcrumb, before the gallery and details row. Full width.noneGood for a banner above the product.
product:details.startIn the right-hand column (below the gallery on mobile), before the product details.noneWraps the whole details block.
product:single.description.startAt the very top inside the product details, before the brand logo and the product name.product
product:single.descriptionInside the details, after the quantity, SKU and availability rows, before the installment widget.productThe usual spot for a size-guide link or a short note.
product:single.description.endAfter the add-to-cart form and product:single.form.end, before the quick-order button.productThe same place as in Twig themes.
product:details.endIn the right-hand column, after the product details and before the add-to-cart form.none
product:single.form.startDirectly before the add-to-cart form.noneThe form holds options, quantity and the add button.
product:single.form.endDirectly after the add-to-cart form, before product:single.description.end.noneGood for trust badges or payment icons.
product:related.startAfter the reviews block, before the related-products slider.noneFull width.
product:related.endAfter the related-products slider, before the testimonials block.none
product:endLast item on the page.noneAfter the testimonials block.

The three product:single.description* slots render once each and pass { product }: .start and .description from the product details, .end from the page itself. Keep an if (!product) return null; guard if you also render one of these names somewhere else.

All the other slots on this page pass no context, so read the product yourself if you need it, for example with useProduct.

Two things to know:

  • The related-products slider and the reviews block render only when scrolled into view, but the slots around them always render.
  • The product reviews block appears only when the store has product ratings turned on. product:related.start renders either way.
app/hooks/index.tsx
import { hookRegistry, HookName, type HookContext } from '@salla.sa/twilight-theme-engine/hooks';
import type { Product } from '@salla.sa/twilight-theme-engine/types';

export function registerThemeHooks() {
  hookRegistry.register(
    HookName.PRODUCT_DESCRIPTION,
    (context: HookContext) => {
      const { product } = context as { product?: Product };
      if (!product) return null;
      return (
        <a className="mb-4 block text-sm text-primary underline" href="/size-guide">
          Size guide for {product.name}
        </a>
      );
    },
    50
  );
}

Call registerThemeHooks() once at module scope, as in Add content to a slot.

Example: trust badges under the add-to-cart form

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

export function TrustBadges() {
  useHook('product:single.form.end', () => (
    <ul className="mt-4 flex gap-4 text-xs text-gray-500">
      <li>Secure payment</li>
      <li>Free returns</li>
      <li>Ships in 2 days</li>
    </ul>
  ));
  return null;
}

Render <TrustBadges /> once under your layout and keep it mounted, so the handler stays registered for the whole visit.

Next

On this page