3.1 KiB
Portal UI conventions — SUI vs Mantine
The portal has two component sources. The rule:
Simple, presentational, brand-defining UI → our SUI design system (
@shared/components). Complex, stateful, or accessibility-hard widgets → Mantine. Don't reinvent what Mantine already does well; do own the look of the simple, high-frequency pieces.
Both are theme-bound: MantineProvider in App.tsx is wired to the portal's
ThemeProvider (mantineTheme.ts maps the brand palette), so Mantine widgets
follow the same light/dark switch and brand colours as SUI. The provider is
intentional — it exists precisely so we can drop Mantine widgets in where they
earn their keep.
Use SUI (@shared/components) — our own style
Layout and presentational primitives we want full brand control over and that are cheap to own:
Button · Card · StatusBadge / MethodBadge · Chip · MetricCard ·
MetricStrip · StatTile · ProgressBar · Avatar · Banner · Skeleton ·
Spinner · EmptyState · NavItem · PanelHeader · SectionDivider ·
Stack / Inline · Table (static/presentational) · CodeBlock ·
FormField (label/help/error layout) · simple Tabs.
Use Mantine — don't reinvent
Anything that needs portals, focus traps, ARIA keyboard patterns, or is just a solved hard problem:
- Overlays:
Modal,Drawer,Popover(focus trap, scroll lock, escape, focus restore) - Menus:
Menu(roving arrow-key navigation) - Selects:
Select/MultiSelect/Combobox/Autocomplete(keyboard + filtering) - Dates:
@mantine/datesDatePicker/DatePickerInput(e.g. billing period range) - Files:
@mantine/dropzoneDropzone(connect-source upload, op-runner sample drop) - Progress UX:
Stepper(multi-step wizards),Notifications,Tooltip - Hooks: prefer
@mantine/hooks(useDisclosure,useClickOutside,useHotkeys, …) over hand-rolling.
Why
Mantine is mature and battle-tested for accessibility. A review of the
hand-rolled SUI overlays found real gaps — Dropdown has no arrow-key
navigation, Modal/Drawer mishandle focus when there are no focusable
children, Toast uses role="alert" for every tone — exactly the things
Mantine gets right. Owning those is wasted effort and an a11y liability.
Known migrations (hand-rolled today → should be Mantine)
These shipped as SUI primitives during the initial build and should move to Mantine equivalents (fixes the a11y findings above):
| Today (SUI) | → Mantine |
|---|---|
Dropdown (menus: tier switcher, app switcher, notifications) |
Menu |
Modal (composer, wizards, settings, create-key) |
Modal |
Drawer (pipeline detail) |
Drawer |
Toast |
notifications |
| new need: billing date range | @mantine/dates |
| new need: file upload | @mantine/dropzone |
Keep Tabs SUI for the simple in-page switchers; only reach for more if a true
tabpanel/roving-focus contract is needed.
Migrating overlays touches visible chrome and behaviour, so do it deliberately (with eyes on the result), not as a blind sweep.