Keep custom admin and vendor UI aligned with @medusajs/ui and Radix UI. Use when adding or modifying reusable UI, page-level interaction patterns, overlays, menus, form primitives, or any custom component in Mercur dashboards.
Use this skill when:
packages/admin or packages/vendorThis skill is the system-level gate for Mercur dashboard UI.
Apply this decision order:
@medusajs/ui@medusajs/ui plus existing local wrappersRadix UI primitives only if the previous options do not cover the interactionBefore writing custom UI, check:
components/common, components/layout, components/modals, or page-local shared components@medusajs/ui already provides the needed primitive or patternadmin-page-ui, admin-form-ui, or admin-tab-ui@medusajs/ui already covers it.radix-ui or @radix-ui/* just because it feels lower-level or more flexible. Use it only when @medusajs/ui does not cover the case.asChild with a child component that fails to spread props or forward refs.Form, ActionMenu, route modal wrappers, or other shared abstractions when they already solve the problem.data-testid coverage for important interaction points.Prefer existing Mercur wrappers when the pattern already exists.
Typical examples in this repo:
Form wrappers for field composition and accessibilityActionMenu for row and section actionsIf a local wrapper exists, extend or reuse it instead of rebuilding the interaction from scratch.
@medusajs/ui secondIf no local wrapper fits, prefer @medusajs/ui.
Use Medusa UI for:
Default assumption:
@medusajs/ui@medusajs/uiIf the exact UI does not exist, first try to compose it from:
@medusajs/uiPrefer composition over custom primitives when the behavior is mostly already solved.
Use Radix only when you need a lower-level primitive not already covered well enough by @medusajs/ui or local wrappers.
Good reasons:
Bad reasons:
asChild and composition rulesMercur already uses asChild heavily. When composing with Medusa UI or Radix:
If those conditions are not true, do not use asChild.
If you genuinely need a new shared component:
components/common, components/layout, or another existing shared subtreeIf the UI is only page-specific and not reusable, keep it local, but still build it from Medusa UI and existing wrappers.
Before finishing, check:
@medusajs/ui?asChild, does the child spread props and forward refs?For non-trivial custom UI: