Skip to main content

Storefront Slots

Storefront slots are containers available in the storefront pages where you can render your UI components. These slots allow you to customize the shopping experience across different pages.

Theme Compatibility
Storefront apps built with NubeSDK are supported on all themes.

Available Slots

These are the slots that are available in the storefront:

SlotPage
before_main_contenthome, product, category, search
after_headerhome, product, category, search, cart
drawer_lefthome, product, category, search, cart
drawer_righthome, product, category, search, cart
before_quick_buy_add_to_carthome, category, search
before_product_grid_item_namehome, category, search
after_product_grid_item_namehome, category, search
before_product_grid_item_pricehome, category, search
after_product_grid_item_pricehome, category, search
product_grid_item_image_top_lefthome, product, category, search
product_grid_item_image_top_righthome, product, category, search
product_grid_item_image_bottom_lefthome, product, category, search
product_grid_item_image_bottom_righthome, product, category, search
before_go_to_checkouthome, product, category, search
before_product_detail_nameproduct
after_product_detail_nameproduct
before_product_detail_priceproduct
after_product_detail_priceproduct
before_product_detail_payment_optionsproduct
after_product_detail_payment_optionsproduct
before_product_detail_shipping_optionsproduct
after_product_detail_shipping_optionsproduct
before_product_detail_add_to_cartproduct
after_product_detail_add_to_cartproduct
after_product_descriptionproduct
before_line_itemscart
before_line_itemcart
after_cart_summarycart
after_go_to_checkoutcart
before_cart_shipping_optionscart
after_cart_shipping_optionscart
before_footerhome, product, category, search
before_section_products_salehome
after_section_products_salehome
before_section_products_newhome
after_section_products_newhome
before_section_products_featuredhome
after_section_products_featuredhome
before_section_newsletterhome
after_section_newsletterhome
before_register_formregister
after_register_formregister
before_register_form_fieldsregister
after_register_form_fieldsregister
before_register_form_submitregister
after_register_form_submitregister

Slot Visual Reference

Home, Category, and Search Pages

  • before_main_content

Before Main Content Slot

  • after_header

After Header Slot

  • drawer_left

Drawer Left Slot

  • drawer_right

Drawer Right Slot

  • before_go_to_checkout

Before Go to Checkout Slot

  • before_footer

Before Footer Slot

Home Page Section Slots

The home page is composed of stackable sections. These slots let you inject content immediately before or after a product section, so your content flows with the page layout instead of overlapping existing content.

Each slot is available only on the home page and is rendered only when its corresponding section is present in the merchant's home layout. If the merchant has not added that section to their home page, the related slots will not render.

Sale Products Section

  • before_section_products_sale
  • after_section_products_sale

Before and After Section Products Sale Slots

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_section_products_sale", [
<Box key="sale-banner">
<Text>🔥 Limited-time deals — up to 50% off!</Text>
</Box>,
]);
}

New Products Section

  • before_section_products_new
  • after_section_products_new

These slots inject content immediately before or after the new products section on the home page.

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_section_products_new", [
<Box key="new-banner">
<Text>✨ Just landed — check out our latest arrivals!</Text>
</Box>,
]);
}
  • before_section_products_featured
  • after_section_products_featured

These slots inject content immediately before or after the featured products section on the home page.

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_section_products_featured", [
<Box key="featured-banner">
<Text>⭐ Handpicked favorites, just for you.</Text>
</Box>,
]);
}

Newsletter Section

  • before_section_newsletter
  • after_section_newsletter

These slots inject content immediately before or after the newsletter section on the home page.

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_section_newsletter", [
<Box key="newsletter-banner">
<Text>📬 Subscribe and get 10% off your first order!</Text>
</Box>,
]);
}

Product Grid Slots

Product grid slots are special slots that allow you to render components on product cards within product grids. These slots include:

  • product_grid_item_image_top_left
  • product_grid_item_image_top_right
  • product_grid_item_image_bottom_left
  • product_grid_item_image_bottom_right
  • before_product_grid_item_name
  • after_product_grid_item_name
  • before_product_grid_item_price
  • after_product_grid_item_price

Product Grid Slots

Rendering Components in Product Grids

To render components in product grids, return an array of components where the root element for each product includes the key prop set to that product's ID. This allows your app to render components across multiple items in the grid.

import { Text } from "@tiendanube/nube-sdk-jsx";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
const productIds = [1, 2, 3];
nube.render("product_grid_item_image_top_left", () => {
return productIds.map((id) => <Text key={id}>ID: {id.toString()}</Text>);
});
}

For a complete example of rendering components dynamically in product grids, see the Dynamic Product Grid Rendering section below:

Product Page Slots

  • before_product_detail_name
  • after_product_detail_name
  • before_product_detail_price
  • after_product_detail_price
  • before_product_detail_payment_options
  • after_product_detail_payment_options
  • before_product_detail_shipping_options
  • after_product_detail_shipping_options
  • before_product_detail_add_to_cart
  • after_product_detail_add_to_cart

Product Page Slots Overview

  • before_product_detail_price

Before Product Detail Price Slot

  • after_product_detail_price

After Product Detail Price Slot

  • before_product_detail_payment_options

Before Product Detail Payment Options Slot

  • after_product_detail_payment_options

After Product Detail Payment Options Slot

  • before_product_detail_shipping_options

Before Product Detail Shipping Options Slot

  • after_product_detail_shipping_options

After Product Detail Shipping Options Slot

  • before_product_detail_add_to_cart

Before Product Detail Add to Cart Slot

  • after_product_detail_add_to_cart

After Product Detail Add to Cart Slot

  • after_product_description

After Product Description Slot

Cart Page Slots

  • before_line_items

Before Line Items Slot

  • before_line_item

The key prop must be set to the line item's ID for each component.

export function App(nube: NubeSDK) {
nube.render("before_line_item", (state) => {
return state.cart.items.map((item) => <Text key={item.id}>Content</Text>);
});
}

Before Line Item Slot

  • after_cart_summary

After Cart Summary Slot

  • after_go_to_checkout

After Go to Checkout Slot

  • before_cart_shipping_options

Renders immediately before the shipping options on the cart page.

Before Cart Shipping Options Slot

  • after_cart_shipping_options

Renders immediately after the shipping options on the cart page.

After Cart Shipping Options Slot

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("after_cart_shipping_options", [
<Box key="shipping-note">
<Text>Free shipping on orders over $50.</Text>
</Box>,
]);
}

Register Page Slots

  • before_register_form
  • after_register_form
  • before_register_form_fields
  • after_register_form_fields
  • before_register_form_submit
  • after_register_form_submit

These slots are available on the storefront register page, where customers create a new account. Use them to inject custom content around the registration form, its fields, or its submit button.

The before_register_form and after_register_form slots wrap the entire form, while the remaining slots let you target more specific areas: around the group of form fields, or around the submit button.

  • before_register_form

Renders immediately before the registration form.

Before Register Form Slot

  • after_register_form

Renders immediately after the registration form.

After Register Form Slot

  • before_register_form_fields

Renders inside the form, immediately before the registration fields.

Before Register Form Fields Slot

  • after_register_form_fields

Renders inside the form, immediately after the registration fields (and before the submit button).

After Register Form Fields Slot

  • before_register_form_submit

Renders inside the form, immediately before the submit button.

Before Register Form Submit Slot

  • after_register_form_submit

Renders inside the form, immediately after the submit button.

After Register Form Submit Slot

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("after_register_form_fields", [
<Box key="register-terms">
<Text>By creating an account you agree to our terms and conditions.</Text>
</Box>,
]);
}

Examples

Adding Content to Product Page

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("after_product_detail_name", [
<Box key="product-badge">
<Text>Free Shipping Available!</Text>
</Box>,
]);
}

Adding Content Before Add to Cart

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_product_detail_add_to_cart", [
<Box key="size-guide">
<Text>View Size Guide</Text>
</Box>,
]);
}

Adding Content Around Payment Options

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_product_detail_payment_options", [
<Box key="payment-banner">
<Text>Up to 12 interest-free installments available.</Text>
</Box>,
]);
}

Adding Content Around the Register Form

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("before_register_form", [
<Box key="register-promo">
<Text>Create an account to track your orders and earn rewards.</Text>
</Box>,
]);
}

Adding Content to Cart Page

import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Box, Text } from "@tiendanube/nube-sdk-jsx";

export function App(nube: NubeSDK) {
nube.render("after_cart_summary", [
<Box key="cart-promo">
<Text>Add $50 more for free shipping!</Text>
</Box>,
]);
}

Dynamic Product Grid Rendering

Product Grid Slots

import { Text } from "@tiendanube/nube-sdk-jsx";
import type { NubeSDK, ProductDetails } from "@tiendanube/nube-sdk-types";
import { styled } from "@tiendanube/nube-sdk-ui";

const StyledText = styled(Text)`
color: red;
font-weight: bold;
`;

export function App(nube: NubeSDK) {
const state = nube.getState();

if (state.location.page.type === "home") {
const sections = state.location.page.data?.sections || [];
const allProducts = sections.reduce((acc: ProductDetails[], section) => {
if (section?.products && Array.isArray(section.products)) {
acc.push(...section.products);
}
return acc;
}, []);

nube.render("product_grid_item_image_top_left", () => {
return allProducts.map((product) => (
<StyledText key={product.id}>ID: {product.id.toString()}</StyledText>
));
});
}
}

This is a Dynamic Product Grid Rendering example that displays a styled badge on the top-left corner of each product image in the home page grid.

const sections = state.location.page.data?.sections || [];
const allProducts = sections.reduce((acc: ProductDetails[], section) => {
if (section?.products && Array.isArray(section.products)) {
acc.push(...section.products);
}
return acc;
}, []);

The previous code flattens all products from all sections into a single array.

nube.render("product_grid_item_image_top_left", () => {
return allProducts.map((product) => (
<StyledText key={product.id}>ID: {product.id.toString()}</StyledText>
));
});

Then, to understand the slot rendering, key={product.id} is required. Links each rendered element to its corresponding product card.

Deprecated Slot Aliases

Some slot names have been renamed for consistency. The old names still work — the SDK automatically redirects them to the new name at runtime — but they are deprecated and may be removed in a future major version.

danger

We recommend updating your code to use the new slot names as soon as possible. The deprecated aliases will continue to work for now, but they may stop working in a future release.

Deprecated nameUse instead
before_price_pdpbefore_product_detail_price
after_price_pdpafter_product_detail_price
before_add_to_cart_pdpbefore_product_detail_add_to_cart
after_add_to_cart_pdpafter_product_detail_add_to_cart
cart_line_item_topbefore_line_item
before_start_checkout_buttonbefore_go_to_checkout

If your app uses both the deprecated name and the new name for the same slot, the new name takes precedence and the deprecated entry is ignored.

Best Practices

  • Always use the product's ID as the key prop when rendering in product grid slots
  • Test your components on multiple themes to ensure consistent compatibility
  • Consider the visual impact of your components on the storefront design
  • Use responsive design principles for components that appear on different screen sizes
  • Clear slots when they're no longer needed using nube.clearSlot()

Help us improve NubeSDK

Found an issue or have a suggestion? Let us know on GitHub.