Skip to main content
This is the canonical list of slots the admin dashboard and the seller panel currently expose. 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.

At a glance

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

page.actions_dropdown

Page tabs slot

page.tabs (default)

Rendered by <PageTabs> at the right edge of any tabbed sub-nav. 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.

Detail-page slots

Every resource detail page renders a slot at the end of its sidebar column, and some also at the end of the main column. The slot name starts with the resource name, and the context key matches it. Host form. On pages marked host form: yes, the slot renders inside the page’s own <form> and exposes it — widgets can bind inputs via useHostForm() that hydrate, dirty-track, and save with the page’s Save button. The form key is what you register extension fields under in formFields. On every other page, widgets own their persistence; use useOptionalHostForm() to write a widget that adapts to both.
On host-form pages your widget renders inside the page’s <form> element, so a <Button> in it submits the page unless you give it type="button".

Products

product.form_sidebar

category.form_sidebar

collection.form_sidebar

catalog.form_sidebar

price_list.form_sidebar

Orders and customers

order.form_sidebar

customer.form_sidebar

company.form_main

company.form_sidebar

Company membership slots

The company’s member list and its “Add member” sheet carry three smaller slots, built for an extension that gives members roles.

Promotions

promotion.form_sidebar

Inventory

purchase_order.form_sidebar

stock_transfer.form_sidebar

Sellers (marketplace)

These slots are on the store owner’s seller management pages in the admin dashboard. For the seller’s own view, see the seller panel slots below.

seller.form_main

seller.form_sidebar

seller_payout.form_main

seller_payout.form_sidebar

Settings

store.form_main

webhook_endpoint.form_sidebar

Seller panel slots

Rendered by the marketplace seller panel (@spree/seller-dashboard) rather than the admin dashboard, and registered the same way, in the seller panel’s own plugins. Their names start with seller. followed by the page — seller.form_main and seller.form_sidebar above belong to the admin dashboard instead. The product page is a host form with the form key seller.product: fields a widget binds with useHostForm() save with the product. The Seller API accepts only the attributes your extension declares in additional_seller_permitted_attributes — see Writable by sellers. The other seller panel pages have no page-wide form, so widgets there save via their own Seller API calls.

Replaceable slots

These slots render built-in content when nothing is registered. Registering a component replaces that content rather than adding to it.

no_store_access

Import the name as NO_STORE_ACCESS_SLOT from @spree/dashboard-core rather than typing it.

getting-started.task.<name>

<name> is the task’s name as the API returns it.

Editor slots (dynamic)

Promotions, price lists, and payment methods each pick their editor by type. The slot names are computed from the type’s api_type shorthand, so registering against the right name is what hooks your editor in. The promotion and price list editor slots replace the built-in editor, which is generated from the type’s preference schema.

promotion.rule_form.<type>

promotion.action_form.<type>

price_list.rule_form.<type>

Payment method editor slots

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>

payment_method.form.<providerType>

payment_method.actions.<providerType>

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; seller.<page>.<area> in the seller panel)
  2. Add <Slot name="..." context={{ resource: order, /* ... */ }} /> at the call site
  3. If the slot sits inside the page’s form, make it a host form: wrap the form in <FormProvider>, hydrate with extensionFormValues('<resource>', record), and merge extensionSubmitValues('<resource>', form) into the save payload — the collection page is the reference
  4. Document the slot here — host, intent, context shape, and form key
  5. Open the PR
The slot is not “live” until the docs land — without an entry here, no plugin author knows it exists.

Reference