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:startproduct:details.startproduct:single.description.startcontext: productproduct:single.descriptioncontext: productproduct:details.endproduct:single.form.startproduct:single.form.endproduct:single.description.endcontext: productproduct:related.startRelated products slider
product:related.endproduct:endSlots
| Slot | Position | Context | Notes |
|---|---|---|---|
product:start | After the breadcrumb, before the gallery and details row. Full width. | none | Good for a banner above the product. |
product:details.start | In the right-hand column (below the gallery on mobile), before the product details. | none | Wraps the whole details block. |
product:single.description.start | At the very top inside the product details, before the brand logo and the product name. | product | |
product:single.description | Inside the details, after the quantity, SKU and availability rows, before the installment widget. | product | The usual spot for a size-guide link or a short note. |
product:single.description.end | After the add-to-cart form and product:single.form.end, before the quick-order button. | product | The same place as in Twig themes. |
product:details.end | In the right-hand column, after the product details and before the add-to-cart form. | none | |
product:single.form.start | Directly before the add-to-cart form. | none | The form holds options, quantity and the add button. |
product:single.form.end | Directly after the add-to-cart form, before product:single.description.end. | none | Good for trust badges or payment icons. |
product:related.start | After the reviews block, before the related-products slider. | none | Full width. |
product:related.end | After the related-products slider, before the testimonials block. | none | |
product:end | Last item on the page. | none | After 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.startrenders either way.
Example: a size-guide link in the description
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
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.