Mantine Code Review
Purpose
Review React components using Mantine UI library for accessibility compliance, Styles API correctness, component pattern adherence, and common pitfall detection.
When NOT to Use
- Non-Mantine React components (use general React review)
- Backend code review
- Mantine v6 or earlier (patterns differ)
- Initial development (use
mantine-developingskill instead)
Review Workflow
Step 1: Identify Mantine Files
# Find files using Mantine
grep -r "from '@mantine" --include="*.tsx" --include="*.ts" -l
Step 2: Run Automated Checks
# TypeScript errors
npm run typecheck
# Lint issues
npm run lint
# Check for common issues
grep -rn "disabled.*Tooltip\|Tooltip.*disabled" --include="*.tsx"
grep -rn "Accordion\.Control.*Button\|Button.*Accordion\.Control" --include="*.tsx"
grep -rn "ActionIcon[^>]*>" --include="*.tsx" | grep -v "aria-label"
Step 3: Manual Review
Use CHECKLIST.md for comprehensive review criteria.
Step 4: Report Findings
Format findings by severity:
- CRITICAL: Accessibility violations, invalid HTML
- HIGH: Performance issues, incorrect patterns
- MEDIUM: Style issues, suboptimal approaches
- LOW: Minor improvements, suggestions
Critical Review Areas
1. Accessibility (CRITICAL)
Must check:
// ❌ FAIL: Missing aria-label on icon button
<ActionIcon onClick={handleSearch}>
<IconSearch />
</ActionIcon>
// ✅ PASS: Has aria-label
<ActionIcon aria-label="Search" onClick={handleSearch}>
<IconSearch />
</ActionIcon>
Review for:
- All
ActionIconcomponents havearia-label - All
CloseButtonhavearia-labelor parent hascloseButtonLabel - Heading hierarchy correct (
orderprop on Accordion) - Focus states visible (not removed by custom CSS)
- Keyboard navigation works
2. Nested Interactive Elements (CRITICAL)
Invalid HTML - browsers will break layout:
// ❌ FAIL: Button inside button (Accordion.Control is a button)
<Accordion.Control>
Click here <Button>Delete</Button>
</Accordion.Control>
// ✅ PASS: Button outside Control
<Group>
<Accordion.Control style={{ flex: 1 }}>Click here</Accordion.Control>
<Button>Delete</Button>
</Group>
Check all:
Accordion.Controlhas no Button, ActionIcon, or Link childrenButtonhas no interactive childrenUnstyledButtonhas no interactive children
3. Styles API Usage (HIGH)
Check for anti-patterns:
// ❌ FAIL: Inline style only affects root
<Button style={{ color: 'red' }}>Text won't be red</Button>
// ❌ FAIL: !important hack
<Button className="my-button">...</Button>
.my-button span { color: red !important; }
// ✅ PASS: Correct Styles API usage
<Button styles={{ label: { color: 'red' } }}>Red text</Button>
<Button classNames={{ label: classes.redLabel }}>Red text</Button>
Review for:
- Using
classNamesorstylesprop for inner elements - No
!importantin CSS targeting Mantine components - Correct selector names (check component's Styles API docs)
- CSS variables used appropriately
4. Tooltip on Disabled (HIGH)
Tooltip won't show on truly disabled elements:
// ❌ FAIL: Tooltip invisible
<Tooltip label="Cannot submit">
<Button disabled>Submit</Button>
</Tooltip>
// ✅ PASS: Use data-disabled
<Tooltip label="Cannot submit">
<Button data-disabled onClick={(e) => e.preventDefault()}>
Submit
</Button>
</Tooltip>
5. ActionIcon.Group Structure (HIGH)
Direct children only:
// ❌ FAIL: Wrapped children break styling
<ActionIcon.Group>
<div><ActionIcon><IconEdit /></ActionIcon></div>
</ActionIcon.Group>
// ✅ PASS: Direct ActionIcon children
<ActionIcon.Group>
<ActionIcon aria-label="Edit"><IconEdit /></ActionIcon>
<ActionIcon aria-label="Delete"><IconTrash /></ActionIcon>
</ActionIcon.Group>
6. Select vs Autocomplete (MEDIUM)
// When value MUST be from list → Select
<Select data={countries} />
// When free text is acceptable → Autocomplete
<Autocomplete data={suggestions} />
Review for correct component choice based on requirements.
7. Form Handling (MEDIUM)
Prefer @mantine/form over manual state:
// ❌ Suboptimal: Manual state for each field
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// ✅ Better: useForm hook
const form = useForm({
initialValues: { email: '', password: '' },
validate: { email: (v) => ... }
});
<TextInput {...form.getInputProps('email')} />
Review for:
- Using
useFormfor forms with validation - Using
getInputPropsfor input binding - Correct
type: 'checkbox'for checkbox/switch inputs - Validation configured appropriately
8. Dark Mode Compatibility (MEDIUM)
// ❌ FAIL: Hardcoded colors break dark mode
<Box style={{ background: 'white', color: 'black' }}>
// ✅ PASS: Theme-aware colors
<Box style={{
background: 'light-dark(white, var(--mantine-color-dark-7))',
color: 'light-dark(black, white)'
}}>
// ✅ PASS: Theme color references
<Box bg="gray.0" c="dark.9">
9. Performance (MEDIUM)
Check for:
- Unnecessary re-renders from inline objects/functions
- Missing
useMemo/useCallbackfor expensive operations - Large lists without virtualization
- Heavy components not code-split
// ❌ FAIL: New object every render
<Button styles={{ root: { padding: 10 } }}>
// ✅ PASS: Stable reference
const buttonStyles = { root: { padding: 10 } };
<Button styles={buttonStyles}>
// ✅ PASS: Or use CSS modules
<Button classNames={{ root: classes.button }}>
10. Polymorphic Component Types (LOW)
// When using component prop, ref type changes
const buttonRef = useRef<HTMLButtonElement>(null); // Default
const linkRef = useRef<HTMLAnchorElement>(null); // With component="a"
<Button ref={buttonRef}>Button</Button>
<Button component="a" ref={linkRef} href="/">Link</Button>
Review for TypeScript errors related to ref types.
Review Output Template
## Mantine Code Review: [Component/File]
### Summary
[1-2 sentence overview]
### Critical Issues
- [ ] [Issue description] - [file:line]
### High Priority
- [ ] [Issue description] - [file:line]
### Medium Priority
- [ ] [Issue description] - [file:line]
### Low Priority / Suggestions
- [ ] [Suggestion]
### Accessibility Audit
- [ ] All icon buttons have aria-label
- [ ] No nested interactive elements
- [ ] Keyboard navigation works
- [ ] Focus states visible
### Styles API Audit
- [ ] No !important hacks
- [ ] Correct selector usage
- [ ] Theme-aware colors
### Passed Checks
- [x] [What's good about the code]
Quick Commands
# Find missing aria-labels on ActionIcon
grep -rn "ActionIcon" --include="*.tsx" | grep -v "aria-label"
# Find potential nested interactives
grep -rn "Accordion\.Control" -A5 --include="*.tsx" | grep -E "Button|ActionIcon|Link"
# Find disabled buttons in tooltips
grep -rn "Tooltip" -A3 --include="*.tsx" | grep "disabled"
# Find hardcoded colors
grep -rn "style={{" --include="*.tsx" | grep -E "color:|background:|bg:"
# Find inline style objects (potential perf issue)
grep -rn "styles={{" --include="*.tsx"
Integration
Related skills:
mantine-developing- Development patterns and guidancehermes-code-reviewer- General TypeScript review
For detailed checklist: See CHECKLIST.md
Related Agent
For comprehensive React + Mantine UI guidance that coordinates this and other Mantine skills, use the mantine-ui-expert agent.
Cost Optimization: Use model="haiku" when invoking this agent for routine code reviews. Haiku is sufficient for pattern matching and Styles API validation.
