Skip to main content
This is the canonical list of slots the dashboard currently exposes. The source of truth is the <Slot name="…"> call sites in the dashboard source (linked under Reference below); each entry here records the host page, the slot name, and the context your component receives. If you need a new injection point in a built-in page, open a PR adding <Slot name="..." context={...} /> and a documentation entry here — that’s the contract for new slots.

Ambient context

Ambient context (permissions, store, user merged into every slot’s props) is planned but not wired up yet — today slot components receive only the slot-specific context listed below. Until it lands, read those values with the hooks instead:
The same applies to an entry’s if predicate: it receives the slot context, but not permissions — gate inside the component for now.

Page header slots

Rendered by <PageHeader> (@spree/dashboard-core/components/page-header.tsx) at the top of every detail and list page that uses the shared chrome.

page.actions

WhereTop-right of <PageHeader>, left of any explicit actions prop
UseAdd primary action buttons (e.g., a “Refund” button on the order detail page)
Context{ resource, ...slotContext }resource is the current page’s primary record, when the host passed one to <PageHeader resource={...} />. May be undefined on list pages.

page.actions_dropdown

WhereInside the more-actions () dropdown menu, above the auto-rendered Copy ID / Delete items
UseAdd menu items (<DropdownMenuItem>) for secondary actions
Context{ resource, ...slotContext } — same as page.actions

Detail-page form slots

The resource detail pages each render a slot below their built-in cards. The context key matches the resource name. Host form: on pages marked host form: yes, the slot renders inside the page’s own <form> and the form context is exposed — widgets can bind inputs via useHostForm() that hydrate, dirty-track, and save with the page’s Save button. On pages without one, widgets own their persistence (use useOptionalHostForm() to adapt).

product.form_sidebar

WhereProduct detail page (products/$productId), end of the sidebar column
UseAdd a card scoped to the product being edited (e.g., a “Brand” picker, wishlist stats, sync status from an external system)
Context{ product } — the full Product record from the Admin API
Host formYes — form key product

category.form_sidebar

WhereCategory detail page (products/categories/$categoryId), end of the sidebar column
UseCategory-scoped cards — merchandising rules, feed settings, external sync state
Context{ category } — the Category record (may be briefly undefined while refetching)
Host formYes — form key category

store.form_main

WhereStore settings page (settings/store), end of the main column
UseStore-level settings a plugin owns — integration toggles, account linking
Context{ store } — the full Store record
Host formYes — form key store

order.form_sidebar

WhereOrder detail page (orders/$orderId), end of the sidebar column
UseFraud-check status, shipping-integration state, loyalty points earned
Context{ order } — the full Order record
Host formNo — widgets save via their own API calls

customer.form_sidebar

WhereCustomer detail page (customers/$customerId), end of the sidebar column
UseLoyalty status, support-ticket summary, external CRM links
Context{ customer } — the full Customer record
Host formNo — the page edits through sheets; widgets save via their own API calls

Page tabs slot

page.tabs (default)

Rendered by <PageTabs> at the right edge of any tabbed sub-nav.
WhereAfter the built-in tab strip
UseAppend your own tab(s) to a sub-route — typically for plugin-owned views inside an existing resource (e.g., “Returns” tab on the order detail)
Context{ tabs, ...slotContext }tabs is the array of built-in tabs (so you can inspect or filter by them)
Some pages override slotName to scope tabs to a single resource (e.g., slotName="order.tabs"). The catalog will grow these as we wire them up; today only the default page.tabs name is in production use.

Payment method editor slots (dynamic)

Used by <PaymentMethodForm> to let payment-provider plugins replace pieces of the editor sheet. The slot names are computed per provider type (stripe, bogus, …), so registering against the right name is what hooks your editor in.

payment_method.guide.<providerType>

WhereAbove the preferences form
UseBanner explaining what the integration does, what credentials to use, links to provider docs
ContextPaymentMethodEditorContext (see below)

payment_method.form.<providerType>

WhereIn place of the auto-generated preferences form
UseRender a custom React form when the provider’s preferences are too complex for the generated UI (multi-step OAuth, environment switchers, …)
ContextPaymentMethodEditorContext

payment_method.actions.<providerType>

WhereSheet footer, before Save/Cancel
UseProvider-specific action buttons — “Test connection”, “Rotate keys”, “Open dashboard in provider”
ContextPaymentMethodEditorContext

PaymentMethodEditorContext

Helpers for building the slot name:
Use these instead of constructing the string yourself, so a rename in one place doesn’t silently break your registration.

Adding a new slot

If a built-in page should expose a new injection point:
  1. Pick a name (<resource>.<area>, e.g., order.timeline)
  2. Add <Slot name="..." context={{ resource: order, /* ... */ }} /> at the call site
  3. Document the slot here — host, intent, context shape
  4. Open the PR
The slot is not “live” until the docs land — without an entry here, no plugin author knows it exists.

Reference