Skip to main content
The product, order, and customer detail pages each render a <Slot> in their right-hand sidebar — typically named <resource>.form_sidebar. Widgets rendered into these slots see the current record and can fetch their own data without disturbing the host page. This recipe builds a “Loyalty status” card for the customer detail page: read-only, fetches the customer’s points + tier, shows a spinner while loading, an empty state when there’s no data, and hides itself for staff without the right permission.

The component

Worth noting:
  • storeId in the query key. The dashboard is multi-store; without this, switching stores leaves stale data on screen.
  • staleTime: 30_000 keeps the data fresh enough for a sidebar widget without re-fetching on every focus event.
  • Three states. Loading (<Skeleton>), empty (<Empty>), and loaded. Skipping the empty state ships a card that says “0 points” when really the customer has never been enrolled — different meaning, different UX.
  • Strings are hardcoded for brevity. Real widgets should go through i18n — see Translations.

Register the widget

The permission gate lives inside the component (usePermissions) rather than in an if predicate on the entry — the predicate only receives the slot context today, not ambient permissions (see the slots catalog). position: 50 puts the card near the top of the sidebar (built-in cards typically use 100/200/300). Pick a number based on whether your widget is more or less important than the others — for a “status” card, near the top is right.

When to fetch in the widget vs. read from the host

The pattern above fetches its own data. The alternative is to read it from the resource the host passes:
Choose based on whether the data is hot path for the rest of the page:
DataApproach
Already on the host’s serializer (e.g., customer.tags)Read from the slot context — no extra HTTP
Conditional, expensive, or owned by your pluginFetch in the widget
Sometimes-needed (e.g., gated by feature flag)Fetch in the widget
A widget that always fetches is wasteful when the host already has the data. A widget that reads from the host but the host doesn’t serialize is broken. Match the pattern to the source of truth.

Loading states for the host page

The built-in detail pages render their sidebar only after the record has loaded, so the context record is always set when your widget mounts. If you register into a slot where that’s not guaranteed (check the slots catalog entry), guard defensively:

Reference