Custom Slots
Besides the predefined storefront and checkout slots, a theme can expose its own injection points, called custom slots. This lets a theme developer decide exactly where apps are allowed to render, in places the predefined slots don't cover.
Requires editing the theme
Custom slots are declared inside the theme's template files, so they are only available to stores that can modify their theme code — those with open FTP or running a theme fork. On standard themes, only the predefined slots are available.
Declaring a custom slot in the theme
A theme exposes a custom slot by placing the nubesdk-slot component in a template, with a type that follows the custom slot naming rules:
{{ component('nubesdk-slot', { type: "custom_this_is_a_special_slot" }) }}
Once the theme renders this, the slot custom_this_is_a_special_slot becomes a target that any app on the store can render into.
Naming rules
A custom slot name must:
- Start with the
custom_prefix. - Be written in
snake_case. - Be entirely lowercase.
- Contain only letters, numbers, and underscores (
_) after the prefix.
| Slot name | Valid | Reason |
|---|---|---|
custom_promo_banner | ✅ | Follows every rule. |
custom_promo_banner_2 | ✅ | Digits are allowed. |
custom_promoBanner | ❌ | Not lowercase / not snake_case. |
custom_promo-banner | ❌ | - is not an allowed character. |
promo_banner | ❌ | Missing the custom_ prefix. |
Rendering into a custom slot
From your app, render into a custom slot exactly like any predefined slot — pass its name to nube.render():
import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";
export function App(nube: NubeSDK) {
nube.render("custom_this_is_a_special_slot", [
<Box key="promo">
<Text>Rendered into a theme-defined custom slot 🎉</Text>
</Box>,
]);
}
Clear it the same way:
nube.clearSlot("custom_this_is_a_special_slot");
Type-level validation
The naming rules are enforced at the type level through the CustomUISlot type, so an invalid custom slot name is rejected by TypeScript at the call site of render / clearSlot:
import type { CustomUISlot } from "@tiendanube/nube-sdk-types";
type A = CustomUISlot<"custom_promo_banner">; // "custom_promo_banner"
type B = CustomUISlot<"custom_promoBanner">; // never — not lowercase / snake_case
type C = CustomUISlot<"custom_promo-banner">; // never — invalid character "-"
type D = CustomUISlot<"promo_banner">; // never — missing "custom_" prefix
nube.render("custom_promo_banner", [/* ... */]); // ✅ compiles
nube.render("custom_promo-banner", [/* ... */]); // ❌ type error
Predefined checkout and storefront slots remain direct members of the slot union, so editor autocomplete for the fixed slot names is preserved.
Handling missing custom slots
Because custom slots depend on the theme, an app can't assume a given custom slot exists on the current store. Render into the name you agreed on with the theme; if the theme hasn't declared that slot, there is simply no target for your content.
You can use the Slot Discovery API to detect whether a custom slot is present: the API classifies every slot on the page as either dynamic-section or static, and custom slots are reported in the static bucket — so they show up in getStatic() (and getAll().static).
One caveat: StaticSlot.slotId is typed as CheckoutUISlot | StorefrontUISlot and does not include custom slot names, so a custom_* slotId won't be recognized by that type. Match it with a plain string check (e.g. slot.slotId === "custom_promo_banner").
Related
- Dynamic Section Slots → — slots auto-generated around a theme's dynamic sections.
- Slot Discovery API → — discover which slots (predefined, custom and dynamic) exist on the current page.
Help us improve NubeSDK
Found an issue or have a suggestion? Let us know on GitHub.