.claude/skills/admin-ui-review/SKILL.md
Review admin UI code for consistency with established patterns. Use after writing any UI code in packages/admin to catch anti-patterns — wrong form components, hardcoded strings, missing i18n, incorrect heading levels, manual error rendering, missing data-testid, raw Controller usage.
npx skillsauth add mercurjs/mercur admin-ui-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when:
This skill checks ALL admin UI patterns. For implementation guidance, see:
admin-form-ui — form field patternsadmin-page-ui — page and section patternsadmin-tab-ui — tab patterns in TabbedForm wizardspackages/admin/src/Form.Field (not raw Controller from react-hook-form)Form.Item wrapper (not manual <div className="flex flex-col gap-y-2">)Form.Label (not <Label> from @medusajs/ui)Form.Control around input elementsForm.ErrorMessage (not manual fieldState.error && <span>)* in label text — just omit optional prop<Form.Label optional> is presentForm.Hint component (not custom divs)t("...") from useTranslation()t("scope.fields.field_name.label")t("scope.fields.field_name.placeholder")t("scope.section.header")t("actions.save"), t("actions.cancel"), t("actions.create"), t("actions.delete")t("scope.action.successToast")labelKey: "scope.create.tabs.tab_name" (not raw text)<Heading> (default level, no level prop)<Heading level="h2"> (inside Container/card headers)<Heading level="h2"> (NEVER h1 in tabs)<Heading> inside RouteDrawer.Header<Text size="small"> or <Text size="small" className="text-ui-fg-subtle"><h1>, <h2>, <p> tags — use Heading/Text componentsdefineTabMeta<SchemaType>({...}) (not raw object { id, label, ... })labelKey (i18n key, not label with raw text)validationFields array listing fields for this tabp-16, inner max-w-[720px] + gap-y-8gap-y-8 between sections, gap-y-6 between fieldsgrid-cols-1 gap-4 md:grid-cols-{2,3} (not custom breakpoints)Container className="divide-y p-0" with header px-6 py-4py-16 + centered max-w-[720px]flex items-center justify-end gap-x-2<li> with bg-ui-bg-component shadow-elevation-card-rest rounded-xl p-1.5grid grid-cols-[1fr_28px] (content + delete button)grid grid-cols-[min-content,1fr] (label + input pairs horizontally)<Label size="xsmall" weight="plus" className="text-ui-fg-subtle"> (compact inline labels — NOT Form.Label)className="bg-ui-bg-field-component" for contrast background<IconButton size="small" variant="transparent"> with <XMarkMini />useFieldArray with append/removeForm.Label + Form.Hint + Add <Button size="small" variant="secondary">useWatch + isOptionDisabled pattern when rows select from shared poolActionMenu component (not custom dropdowns)usePrompt() (not window.confirm)NoRecords / NoResults (not custom empty divs)StatusBadge (not custom colored spans)KeyboundForm (not raw <form>)RouteDrawer.Close / RouteFocusModal.Close (not manual navigate)KeyboundForm (not raw <form>)isPending guardisLoading={isPending}toast.success() + handleSuccess() from useRouteModal()isError → throw error for error boundarydata-testid on root elements, form fields, buttonsdata-testid="product-create-title-input"## UI Review: {file_path}
### P1 (Critical)
1. **Raw Controller** at line {N}: Uses `Controller` instead of `Form.Field`
Fix: Replace with `Form.Field` + `Form.Item` + `Form.Label` + `Form.Control` + `Form.ErrorMessage`
2. **Hardcoded string** at line {N}: `"SEO Title *"` should be `t("products.fields.seo_title.label")`
### P2 (Inconsistency)
1. **Wrong heading level** at line {N}: `<Heading level="h1">` in tab — should be `level="h2"`
### P3 (Style)
1. **Missing data-testid** at line {N}: Tab root div missing `data-testid`
## UI Review: {file_path}
No findings. Code follows all admin UI patterns.
Verified:
- Form.Field pattern ✓
- i18n strings ✓
- Correct heading levels ✓
- defineTabMeta ✓
- data-testid ✓
| Anti-Pattern | Correct Pattern |
|-------------|----------------|
| <Controller> | <Form.Field> |
| <Label> from @medusajs/ui | <Form.Label> |
| fieldState.error && <span> | <Form.ErrorMessage /> |
| "Title *" | <Form.Label>{t("...")}</Form.Label> (no optional) |
| _tabMeta = { id: "x" } | defineTabMeta<T>({ id: "x", ... }) |
| <Heading level="h1"> in tab | <Heading level="h2"> |
| window.confirm(...) | usePrompt() |
| <form onSubmit> | <KeyboundForm onSubmit> |
| <div className="flex flex-col gap-y-2"> (field wrapper) | <Form.Item> |
| Hardcoded "Save" | t("actions.save") |
documentation
Analyze a Mercur 1.x project and guide migration to 2.0. Self-contained — works without access to the mercur monorepo.
documentation
Plan and execute migration from Mercur 1.x to 2.0. Classifies project difficulty, reads relevant migration docs, and follows stop conditions.
development
Review code changes for contract compliance, type safety, and regression risk. Use after completing any non-trivial implementation, before merging PRs, or when asked to review code quality across any mercur package.
tools
Use Mercur CLI commands correctly inside a project created from the Mercur basic starter. Use when choosing between `create`, `init`, `add`, `search`, `view`, and `diff`.