> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ollie.shop/llms.txt
> Use this file to discover all available pages before exploring further.

# Slots Catalog

> Every slot of the default checkout template: where it is, what renders there by default, when it shows, and the props a custom component placed in it receives

A [slot](/ollie-shop/concepts/slots.md) is a named position in the checkout where a custom component can be placed. This catalog lists the **89 slots of the default template**, grouped by the page or step they belong to. The grocery and sales templates share most of them.

How to read the table:

* **Default content** is what the template renders there when no component is assigned. Your component receives it as `children`: render `{children}` to keep it and add around it, or leave it out to replace it (see [Children component](/ollie-shop/customization/children-component.md)).
* **When it renders**: `always` means on every load of that page; otherwise the condition or device that makes it appear.
* **Props** are passed to your component on top of `children`. "children only" means the slot passes nothing else; read the checkout state with the [SDK hooks](/ollie-shop/api/index.md) instead.

One component per slot: a store's components are matched by slot id, so two components cannot share a slot. Use **Highlight all slots** or **Inspect slots** in [Studio](/ollie-shop/studio.md) to see these ids on the live preview.

## Dynamic slots

Some ids are patterns. The checkout emits one slot per value, so new payment methods or custom steps get a slot without a catalog update.

| Pattern | The variable is | Use it to |
| - | - | - |
| `payment_option_{{ paymentMethodName }}` | The method id configured for the store: `pix`, `credit_card`, `debit_card`, `boleto`, `paypal`, `apple_pay`, `google_pay`, and so on | Customize the tile of one payment method |
| `payment_{{ paymentType }}_content` | The method's normalized type | Extend the inside of a payment option without replacing the whole tile. See [Payment slots](/ollie-shop/customization/payment-slots.md) |
| `{{ summary }}_summary` | The step's `summary` value, lowercased. `summary: "Contact"` emits `contact_summary` | Replace the collapsed summary row of a step, including a [custom step](/ollie-shop/customization/steps.md) |

## Global

Rendered on every page: header, footer, the two-column layout and the summaries.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `header` | Logo and login row on checkout detail pages; custom header row on the cart page | always | children only |
| `checkout_header_full_page` | Empty, full-width banner area above the two-column layout | always | children only |
| `checkout_summaries` | Contact and shipping summary cards shown after each step completes | always | children only |
| `checkout_sidebar` | Totalizer, coupon form, proceed button | Parent div has a desktop-only class, only visible on lg screens and above; desktop-only | children only |
| `checkout_sidebar_login` | Login prompt | the `showLoginOnSidebar` flag is on | children only |
| `checkout_coupon_form` | Coupon input | always | children only |
| `checkout_sidebar_totalizer` | Totalizer, full price table | always; desktop-only | children only |
| `checkout_sidebar_checkout_button` | Empty, reserved space for custom CTA | always | children only |
| `step_navigation` | Prev/next navigation buttons row | Shown once the shopper has an email, a valid address and shipping quotes | `onToggleSummary`, `paymentsExpressComponent` |
| `step_navigation_total_label` | Total price label inside step navigation bar | always | `handleToggleSummary` |
| `contact_summary` | Contact summary card shown after the contact/shipping step completes | The step has a summary | children only |
| `contact_summary_modal` | The contact-details edit form (passed as children) | Rendered inside the contact-details edit modal. | children only |
| `shipping_summary` | Shipping summary card shown after shipping is selected | The step has a summary | children only |
| `footer` | Footer links content | always | children only |
| `footer_all_container` | Full footer wrapper | always | children only |
| `footer_sidebar` | Sidebar footer section, contains footer slot as default child | always | children only |

> **Notes on global slots**
>
> * `header`: Same slot ID renders in two different locations simultaneously. A custom component registered here appears in BOTH the cart page and all checkout detail pages.
> * `checkout_header_full_page`: Void slot. Not rendered in full-page display mode.
> * `checkout_summaries`: The slot always renders. Its default content only appears once a step is complete, but a custom component injected here is always mounted.
> * `checkout_sidebar_totalizer`: Desktop-only. A component placed here does not render below lg. The default content is the store's full price table, so render \{children} unless you intend to replace the totals. Device constraint is inherited from the parent container, which is hidden below lg.
> * `checkout_sidebar_checkout_button`: Void slot. No default content.
> * `step_navigation`: Slot itself has no conditional, the parent nav element carries the a mobile-only class when showNavigation is false.
> * `step_navigation_total_label`: Default child has 'sm:hidden', only visible below sm breakpoint. The slot itself always renders.
> * `contact_summary`: Only rendered when the step has a summary.
> * `contact_summary_modal`: Wraps the contact-details edit form as `children`, inject a custom component to render content around the form (legal/compliance notice, an extra field, a banner) without replacing it. No context props: reach customer/locale/session via `useCheckoutSession()`, the same hook the form uses. Only the contact-details form is wrapped; the email-only and user-identified modal states are not.
> * `shipping_summary`: Only rendered when the step has a summary, like contact\_summary.
> * `footer`: Void slot, default child of footer\_sidebar.
> * `footer_sidebar`: Inner default div conditionally uses a below-desktop-only class based on hasSidebarFooter and hasFullWidth. Slot itself always renders.

## Cart page

The cart page: items, totals, coupon, delivery method and the proceed-to-checkout actions.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `cart_empty` | Empty cart message | The cart is empty | children only |
| `cart_header_full_page` | Empty, full-width banner area on cart page | always | children only |
| `cart_title` | h1 with cart title and item count | always | children only |
| `cart_delivery_method_selector` | Link to the other way of receiving the cart ("Receber em casa" on pickup, "Retirar na loja" on delivery); nothing while that method cannot take the cart | enableShippingSimulationCta on and the cart has a shipping address (before that the same spot holds the native "calculate shipping" link, which is not a slot) | `deliveryMethodOptions`, `defaultValue`, `onChange`, `isPending` |
| `cart_items` | Full item list | always | children only |
| `cart_item` | Single item row | always | `item`, `onQuantityChange`, `onRemoveItem`, `formatPrice`, `isUnavailable` |
| `cart_item_addons` | Empty | always | `item` |
| `cart_item_details` | Empty | always | `item` |
| `cart_coupon_form` | Coupon code input | Below md on the cart page; also in the desktop cart sidebar and the summary modal | children only |
| `cart_totalizer` | Totalizer (mobile), default child has a below-desktop-only class | always | children only |
| `cart_mobile_summary` | Wrapper around the mobile cart footer: cart\_coupon\_form (a mobile-only class) + cart\_totalizer (a below-desktop-only class) | always | children only |
| `cart_sidebar` | Coupon, totalizer, express checkout, proceed button | Parent div has a desktop-only class, only visible on lg screens and above; desktop-only | children only |
| `cart_sidebar_login` | Login prompt | the `showLoginOnSidebar` flag is on | children only |
| `cart_sidebar_totalizer` | Totalizer with package info | always | children only |
| `cart_sidebar_checkout_button` | Express checkout area with proceed button | always | `paymentsExpressComponent` |
| `cart_express_wrapper` | Express checkout buttons | Express checkout is configured: below desktop width on the cart page, and in the cart sidebar | `paymentsExpressComponent` |
| `cart_mobile_navigation` | Full mobile bottom navigation bar | Parent nav has a below-desktop-only class, only visible below lg breakpoint; mobile-only | `onToggleSummary`, `paymentsExpressComponent` |
| `cart_mobile_navigation_total_label` | Total price display in mobile nav | Inherited from parent cart\_mobile\_navigation (a below-desktop-only class); mobile-only | children only |
| `cart_proceed_to_checkout_button` | Primary proceed to checkout button | Inherited from parent cart\_mobile\_navigation (a below-desktop-only class); mobile-only | `nextStepUrl` |
| `cart_address_card` | Address card inside cart list | Rendered inside the cart list when address card is needed | children only |
| `cart_address_card_wrapper` | Wrapper around cart address card | Rendered inside the cart list | children only |
| `cart_digital_banner` | Info banner above the digital package group (immediate delivery by email) | Digital packages exist in the session (package type 'digital') | children only |
| `cart_items_package_list_item` | Whole package card in the cart item list (header + items) | One shipping package with at least one available item | `shippingPackage`, `itemsInPackage`, `itemsCountInPackage` |
| `cart_items_package_list_item_header` | Package group header in cart item list | Rendered inside the cart list when package group header is needed | children only |
| `items_gallery_modal_content` | Items gallery modal content | Rendered inside the items gallery when the modal is opened | children only |
| `items_gallery_item_content` | Individual item content inside gallery modal | Rendered inside the items gallery when the modal is opened | children only |

> **Notes on cart page slots**
>
> * `cart_empty`: Early return, when this slot renders, the rest of the cart page does not.
> * `cart_header_full_page`: Void slot.
> * `cart_delivery_method_selector`: Drawing delivery / pickup on the cart as a two-option selector, or restyling the link, without reimplementing the switch. Same contract as shipping\_delivery\_method\_selector. `deliveryMethodOptions` holds the methods the store has on among delivery and pick\_up (never custom), each `{ value, label, icon, disabled, loading }`: `disabled` while a switch runs or the method cannot take the cart (no store quoted for pickup; delivery still being checked at the shopper's address, which also sets `loading`). `defaultValue` is the method the cart is on. `onChange(value)` runs the native switch for the whole cart, the one the step's selector runs; with autoSelectNearestPickupPoint off, choosing pick\_up opens the store selector instead. `isPending` is true while the switch runs. A failed switch puts `defaultValue` back and the host shows the error message. The slot stays mounted when the native link is hidden (children is then empty), so a component can show the held-back option. It is a flex item of the title row, after the title: next to it from 1024px, wrapping below it under that.
> * `cart_item`: Rendered once per item in the cart items via renderItem callback.
> * `cart_item_addons`: Rendered inside cart\_item default content, once per item. **Context props arrive at the TOP LEVEL of the component signature, not inside `props`**. Availability signal is `item.available === false`, not `isUnavailable`. Prices are in cents, divide by 100 for display.
> * `cart_item_details`: Rendered inside cart\_item default content, once per item, BETWEEN the product title and the unit-price block. Empty by default, good place for per-item badges/tags. **Context props arrive at the TOP LEVEL of the component signature, not inside `props`**. Prices are in cents, divide by 100 for display.
> * `cart_coupon_form`: Shared slot ID, same component renders in three locations simultaneously: mobile area, desktop sidebar, and cart modal.
> * `cart_totalizer`: Slot always renders. Default child has a below-desktop-only class, hides on large screens. A custom override does NOT inherit this CSS.
> * `cart_mobile_summary`: Override or wrap the whole mobile cart footer (coupon + totalizer) as a single region. Slot itself always renders, the child slots keep their own responsive gating (cart\_coupon\_form a mobile-only class, cart\_totalizer child a below-desktop-only class). A custom override replaces the whole region and does NOT inherit those CSS classes.
> * `cart_sidebar_totalizer`: Reachable on mobile through the summary modal, so it is a valid choice for a component that must appear on phones. On desktop both contexts are live at once, so one record produces two instances, design for that or pick a single-context slot. The default content is the store's price table, so render \{children} unless you intend to replace the totals. Shared slot ID. Not desktop-only: the modal context carries it below lg. The desktop duplication is the sidebar instance plus the modal instance rendering together.
> * `cart_sidebar_checkout_button`: Receives the `paymentsExpressComponent` prop, a ready-made express checkout element.
> * `cart_express_wrapper`: Shared slot ID. On the cart page it sits in the below-desktop navigation. Renders only when express checkout is configured.
> * `cart_address_card_wrapper`: Rendered inside the cart list.
> * `cart_digital_banner`: The default content styles with the theme's secondary palette and can be restyled via the --digital-banner-bg and --digital-banner-text-color tokens.
> * `cart_items_package_list_item`: Replace or restyle an entire package card, or hide selected packages by returning nothing for them. Wraps the package card, so a custom component that renders nothing removes that package from the list. Mounts once per package.
> * `cart_items_package_list_item_header`: Rendered inside the cart list.
> * `items_gallery_modal_content`: Rendered inside the cart list.
> * `items_gallery_item_content`: Same three-file shared context as items\_gallery\_modal\_content.

## Shipping step

Choosing delivery or pickup, the quotes, packages and pickup points.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `contact_email_form` | The email form of the identification step, under the 'Please, enter your email to continue' heading: email input with the Apply button and the typo suggestion ('did you mean ...') | The shopper has not identified yet | `email`, `onSubmit`, `isSubmitting`, `autoFocus`, `isValidEmail`, `getEmailSuggestions` |
| `shipping_address_autocomplete` | Address capture shown right after the email: postal code autocomplete for BRA/MEX, street autocomplete with a postal-code fallback elsewhere, plus the mobile-only 'use my location' button | The shopper has an email but no valid address yet | `onSubmit`, `isLoading`, `error`, `isAskingPostalCode`, `pendingAddress`, `onEditAddress` |
| `shipping_title` | h1 delivery options heading | The delivery method selector is shown, or the purchase ships as a single package | children only |
| `shipping_list_packages` | Shipping package list (SLAs) | The cart has packages of that type (delivery, pickup or digital) | `type` |
| `shipping_package_unavailable` | Unavailable items notice | Some items cannot be shipped | `items` |
| `shipping_package_shipping_options` | Shipping options list per package | A standard (not custom) delivery is selected | children only |
| `shipping_package_shipping_options_item` | A single shipping option row (label, carrier name, price) | One instance per shipping quote, inside shipping\_package\_shipping\_options | `option`, `selectedPackage`, `isSelected`, `price`, `label`, `formatPrice`, `onSelect`, `disabled`, `isLoadingOptions` |
| `shipping_package_unavailable_item` | Individual unavailable item row | Rendered by the host when unavailable items exist | children only |
| `shipping_package_items_gallery` | Package thumbnail row: item images, quantity badges and the "Detalhes" link | Shipping or pickup package with at least one item | `shipping`, `packageNumber`, `cartItems`, `formatPrice`, `compact`, `onDetailsClick` |
| `shipping_pickup_receiver_form` | "Responsável pela retirada" heading plus first-name / last-name inputs | Pickup package, shopper unchecks "Cliente irá retirar os itens" (or the saved receiver differs from the shopper). Not rendered for read-only (identified, not logged in) sessions. | `inputs`, `receiver`, `onSaveReceiver`, `packageSelected` |
| `shipping_delivery_method_selector` | Delivery method selector (pickup vs delivery tabs) | More than one delivery method is available | `deliveryMethodOptions`, `defaultValue`, `onChange` |
| `shipping_address_card` | Address card for the selected delivery address | Inside pickup or delivery section, only renders when that section has packages | `address`, `onEditAddress` |

> **Notes on shipping step slots**
>
> * `contact_email_form`: Replacing the email form of the identification step with a custom one, e.g. a different layout, extra copy or a consent checkbox, or a different validation rule, while keeping the host identification flow. onSubmit(email) runs the same identification as the native Apply button (auto-pickup, identified-user modal, redirect to the shipping step when the session needs it) without validating the format: validate in the component first, with isValidEmail(email) to reuse the native rule. It trims the value and does nothing for an empty email or the one already on the session. isSubmitting is true while the request runs; server errors are shown by the host as messages. getEmailSuggestions(email) returns \{ hasSuggestions, suggestion } for common domain typos, as the native form uses. email is the email already on the session (empty here, since the slot only mounts before identification). The heading stays outside the slot. The email form inside the email edit modal is not wrapped.
> * `shipping_address_autocomplete`: Replacing or decorating the first address input of the shipping step, including a fully custom autocomplete that keeps the native request, loading, error and postal-code behavior in its own layout. onSubmit(address) runs the same request as the native UI: the auto-pickup action when the store has autoSelectPickup, UPDATE\_SHIPPING\_ADDRESSES otherwise, with country and address type filled in. It does not resolve a Places id: search with useAddress().searchPredictions / predictions and call useAddress().selectPrediction(id) before submitting. An address without postalCode, in a country that requires one, is not sent; isAskingPostalCode turns true and pendingAddress holds that address (also when the platform rejects it for a missing postal code). The default children switch to the postal-code field by themselves; a component that replaces them renders its own field while isAskingPostalCode is true, submits onSubmit(\{ ...pendingAddress, postalCode }), and calls onEditAddress() to go back to the search. useAddress().lookupByPostalCode(postalCode, country) fills in city and state like the native field does. isLoading covers both the prediction search and the submit. Failed submits are reported as messages by the host. On stores without autoSelectPickup an address submitted with a postal code unmounts the slot while the request runs and the page shows the shipping skeleton; a failure mounts it again with fresh local state.
> * `shipping_title`: Appears in two files with different conditions. Both must be true for the slot to render in its respective context.
> * `shipping_list_packages`: Rendered up to three times, once for each package type (delivery, pick\_up and digital) the cart has. Digital packages are never produced by platform parsing; they only exist when a custom function sets package type 'digital', and the default content is an info banner (immediate delivery by email) plus an items gallery (no address, no shipping options).
> * `shipping_package_shipping_options_item`: Changing how one option looks or behaves without reimplementing the whole list. The same custom component renders for every option, so branch on `option` and return `children` for the ones you leave alone. `onSelect()` is the native selection (which opens the time-slot modal when the quote has timeSlots); to commit a slot yourself, dispatch UPDATE\_SHIPPING\_PACKAGES with `{ id: option.id, items: selectedPackage.items, addressId: selectedPackage.addressId, selectedTimeSlotId }`.
> * `shipping_package_unavailable_item`: Shared, same ID appears in shipping unavailable list and cart page unavailable list.
> * `shipping_package_items_gallery`: Customizing how a package's items are previewed, per package (e.g. different treatment for pickup vs delivery, or for a given package number). One instance per package. `shipping` is the ShippingPackage the row stands for (`type` tells pickup from delivery). `onDetailsClick()` opens the package details modal. `children` is the native row, so returning it keeps the default.
> * `shipping_pickup_receiver_form`: Changing the fields asked of whoever collects the order (extra fields, masks, copy) without touching the rest of the pickup card. One instance per pickup package. `receiver` is `{ firstName, lastName }` as saved; `onSaveReceiver({ firstName, lastName })` writes it as the pickup address's receiverName (UPDATE\_SHIPPING\_ADDRESSES). `inputs` are the native fields' props (their onBlur saves), for augmenting rather than replacing. The checkbox above stays native: unchecking it resets the receiver to the shopper.
> * `shipping_address_card`: Rendered in both the pickup and the delivery sections.

## Address step

The address form shown when the shopper's address is missing or incomplete.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `address_page` | Full address step (form + navigation) | Shown once an address is selected and the shopper is identified | `stepNavigation` |
| `shipping_address_details_form` | Address fields | Shown once an address is selected and the shopper is identified | children only |

> **Notes on address step slots**
>
> * `address_page`: stepNavigation prop is an object with \{ props: StepNavigationProps, Component: (navigationProps) => JSX.Element }, allows custom component to render navigation primitives.
> * `shipping_address_details_form`: Always renders when address\_page renders. Nested inside address\_page slot default content.

## Payment step

Payment options, their contents, installments and the place-order button.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `payment_method_options` | Payment method tab selector | always | children only |
| `payment_option_gift_card` | Gift card form | always | children only |
| `saved_card_options` | Saved card selector | The shopper has saved cards | children only |
| `checkout_totalizer` | Totalizer (mobile), default child div has a mobile-only class | always | children only |
| `checkout_mobile_summary` | Wrapper around the mobile-only payment-step summary footer (a mobile-only class div containing checkout\_totalizer) | always | children only |
| `payment_option_pix` | PIX payment content | The shopper selects the PIX tab | children only |
| `payment_option_credit_card` | Credit card form | The shopper selects the credit card tab | children only |
| `payment_option_promissory` | Promissory note form | The shopper selects the promissory tab | children only |
| `payment_option_paypal` | PayPal content | The shopper selects the PayPal tab | children only |
| `payment_option_apple_pay` | Empty, void slot, no default child | The shopper selects the Apple Pay tab | children only |
| `payment_option_google_pay` | Empty, void slot, no default child | The shopper selects the Google Pay tab | children only |
| `payment_option_click_to_pay` | Empty, void slot, no default child | The shopper selects the Click to Pay tab | children only |
| `payment_option_pagaleve_parcelado` | PagaLeve installments content | The shopper selects the PagaLeve tab | children only |
| `payment_option_pagaleve_avista_transparente` | PIX content (reused for this PagaLeve variant) | The shopper selects this PagaLeve option | children only |
| `payment_option_pagaleve_parcelado_transparente` | PagaLeve installments content | The shopper selects this PagaLeve option | children only |
| `payment_option_pagaleve_mensal_transparente` | PagaLeve installments content | The shopper selects this PagaLeve option | children only |
| `payment_option_affirm` | Affirm BNPL content | The shopper selects the Affirm tab | children only |
| `payment_option_nubank` | NuPay content | The shopper selects the Nubank tab | children only |
| `payment_option_boleto_parcelado_koin` | Boleto Parcelado Koin content | The shopper selects the Boleto Parcelado Koin tab | children only |

> **Notes on payment step slots**
>
> * `payment_method_options`: Slot is unconditional. The options are dimmed when gift cards pay the whole order, but the slot itself always renders.
> * `payment_option_gift_card`: Always rendered, outside the payment method tabs.
> * `checkout_totalizer`: Slot always renders in payment step. Default child has a mobile-only class. A custom override does NOT inherit this CSS class.
> * `checkout_mobile_summary`: Override or wrap the whole mobile payment-step summary footer as a single region. Checkout analog of cart\_mobile\_summary. Slot itself always renders; the default child div is a mobile-only class so the totalizer only shows below md. A custom override replaces the whole region and does NOT inherit that CSS class.
> * `payment_option_credit_card`: NEVER place a CTA or confirm button here, component does not exist in DOM until user clicks the credit card tab.
> * `payment_option_paypal`: Both PayPal payment methods render this slot.
> * `payment_option_apple_pay`: Self-closing slot. The Apple Pay button itself is rendered separately when Apple Pay is selected.
> * `payment_option_google_pay`: Self-closing slot.
> * `payment_option_click_to_pay`: Self-closing slot.
> * `payment_option_boleto_parcelado_koin`: Authorization is off-site: the order finishes with a redirect to Koin's hosted checkout, so anything rendered here is pre-redirect content only.

## Order confirmation

The page shown after the order is placed.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `order_header` | Logo / header row on confirmation page | The order has loaded | children only |
| `order_details` | Full order details (contact, shipping, payment summaries) | The order has loaded | children only |
| `order_totalizer` | Totalizer, order totals | The order has loaded | children only |
| `order_footer` | Footer / continue shopping row | The order has loaded | children only |

> **Notes on order confirmation slots**
>
> * `order_details`: order\_totalizer is nested inside this slot's default content.
> * `order_totalizer`: Nested inside order\_details default content.

## Modals and on-action

Mounted when the shopper opens a modal or triggers an action, not on page load.

| Slot id | Default content | When it renders | Props your component receives |
| - | - | - | - |
| `modal_user_identified` | User identified modal | The modal is open | `onClose`, `showModal` |
| `modal_profile_summary` | Profile summary card inside email edit modal | The shopper's first name is known | children only |
| `modal_change_delivery_address` | Delivery address selection modal | The modal is open | `onChange`, `onShowNewAddressModal`, `onClose` |
| `modal_change_pickup_address` | Pickup address selection modal | The modal is open | `onChange`, `onChangeType`, `onClose` |
| `modal_new_address_form` | The whole new address form: address and receiver fields plus the Back and Save buttons | 'New address' clicked in the delivery address modal | `mode`, `address`, `addressForm`, `onSubmit`, `isSubmitting`, `onBack`, `onClose` |
| `modal_edit_address_form` | The whole change address form: address and receiver fields plus the Back and Save buttons | 'Change' clicked on a saved address in the delivery address modal | `mode`, `address`, `addressForm`, `onSubmit`, `isSubmitting`, `onBack`, `onClose` |
| `modal_complete_address_form` | The whole complete the address form: street summary with the Change link, number field with the no number checkbox, complement field and the Save button | The delivery address card is edited while the selected address has no number and the completeAddressModal store flag is on | `address`, `onSubmit`, `isSubmitting`, `onChange`, `onClose`, `withoutNumberValue` |
| `modal_shipping_address` | Postal code / address autocomplete input with a 'Calculate shipping' action | Rendered inside the 'Calculate shipping' modal on its postal-code step, the initial step when the session has no shipping address, or after onBackToAddress is called from modal\_shipping\_options | `onSubmit`, `isSubmitting`, `error` |
| `modal_shipping_options` | Address summary with a 'Change' action, the list of delivery/pickup quotes, and the 'Save shipping option' button | Rendered inside the 'Calculate shipping' modal on its shipping-options step, the initial step when the session already has a shipping address, or after onSubmit resolves in modal\_shipping\_address | `selectedQuote`, `onSelectQuote`, `onSave`, `onBackToAddress` |
| `modal_shipping_unavailable_summary` | One red-bordered line with the unavailable item count, a thumbnail strip of those items and a chevron | Rendered last in the packages step of the 'Calculate shipping' modal when at least one cart item cannot be shipped to the current address | `items`, `onClick`, `expanded` |

> **Notes on modals and on-action slots**
>
> * `modal_user_identified`: The slot has no condition of its own; it shows whenever the modal is open.
> * `modal_new_address_form`: Replacing the new address form of the delivery address modal with a custom one, e.g. to add a field, while keeping the host save, loading and error handling. Same props as modal\_edit\_address\_form, with mode new and address as the optional prefill. On success the host runs its onSuccess or closes the modal. See modal\_edit\_address\_form for the onSubmit contract.
> * `modal_edit_address_form`: Replacing the change address form of the delivery address modal with a custom one, e.g. to add a field, while keeping the host save, loading and error handling. mode is 'new' or 'edit'; address is the address being edited, or the prefill for a new one. onSubmit(address) runs the host's save (UPDATE\_SHIPPING\_ADDRESSES) without validating: validate in the component first, or use addressForm (the host's useAddressForm return, with validate() and getValues()) to reuse the native rules. In edit mode the values are written over the address being edited, so its id is kept. isSubmitting is true while the save runs; on success the host closes the modal (or, in new mode, runs its onSuccess), on failure it shows an error message. onBack returns to the address list, onClose closes the modal. The save only persists address fields and drops unknown keys, so an extra field has to be stored by the component itself before calling onSubmit.
> * `modal_complete_address_form`: Replacing the complete the address form with a custom one, e.g. to ask for an extra field or change the no number rule, while keeping the host save, loading and error handling. onSubmit(values) writes the values over the address being completed, so its id and the fields the modal doesn't show are kept, and runs the host's save (UPDATE\_SHIPPING\_ADDRESSES) without validating: validate in the component first. withoutNumberValue is the value the host persists for an address with no number ('S/N'); send it as number to reproduce the native checkbox. isSubmitting is true while the save runs; on success the host closes the modal, on failure it shows an error message. onChange closes this modal and opens the delivery address selection modal, onClose closes it. The save only persists address fields and drops unknown keys, so an extra field has to be stored by the component itself before calling onSubmit.
> * `modal_shipping_address`: Replacing the address capture step of the shipping simulation modal. Call onSubmit(address) with a resolved address containing postalCode to advance to modal\_shipping\_options. Second step of a two-step modal, paired with modal\_shipping\_options. onSubmit runs the address update action; the host switches to the options step on success and feeds `error` back on failure.
> * `modal_shipping_options`: Replacing the quote selection step of the shipping simulation modal. Call onBackToAddress() to send the user back to the address form (modal\_shipping\_address). First step of a two-step modal, paired with modal\_shipping\_address. Only modal-local state is passed as props, the quotes (session.shipping.availableQuotes), the address (session.shipping.addresses) and the locale for price formatting come from useCheckoutSession(); the saving state comes from usePendingActions() as pendingActions.includes('UPDATE\_SHIPPING\_PACKAGES'). onBackToAddress clears the selected quote and flips the host state to the address step; onSave persists the selected quote and closes the modal.
> * `modal_shipping_unavailable_summary`: Replacing the one-line summary of the items that cannot be shipped, e.g. to add a remove or pickup action inline. items are the unavailable cart items. onClick opens their detail view. expanded is undefined when the row leads to another view and a boolean when it is a disclosure; the default row picks its chevron from it.

## Related

* [Slots](/ollie-shop/concepts/slots.md): the concept
* [Build Your First Component](/ollie-shop/components/your-first-component.md): placing a component in a slot
* [Ollie Studio](/ollie-shop/studio.md): find a slot on the live preview


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.