Claude-skill-registry-data mantine-developing
Build React UIs with Mantine component library. Customize styles with Styles API, handle forms with @mantine/form, implement theming, and avoid accessibility pitfalls. Use when creating Mantine components or fixing styling issues.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/mantine-developing" ~/.claude/skills/majiayu000-claude-skill-registry-data-mantine-developing && rm -rf "$T"
data/mantine-developing/SKILL.mdMantine UI Development
Purpose
Build React UIs with Mantine's component library, Styles API for customization, and @mantine/form for form handling.
When NOT to Use
- Basic React development (Claude knows this)
- Non-Mantine UI libraries (Material UI, Chakra, etc.)
- Simple HTML/CSS without Mantine
- Mantine v6 or earlier (this skill covers v7+)
Quick Start
Step 1: Import Components
// Core components import { Button, TextInput, Select, Modal } from '@mantine/core'; // Hooks import { useDisclosure, useToggle } from '@mantine/hooks'; // Form handling import { useForm } from '@mantine/form';
Step 2: Basic Component Usage
<Button variant="filled" color="blue" size="md" loading={isLoading}> Submit </Button> <TextInput label="Email" placeholder="your@email.com" error={errors.email} required />
Step 3: Customize with Styles API
See Core Patterns below.
Step 4: Validate Accessibility
- Add
to icon-only buttonsaria-label - Check keyboard navigation works
- Verify focus states are visible
Core Patterns
Styles API (Critical)
Mantine components have multiple inner elements. Use Styles API to target them:
// Option 1: classNames prop (recommended for CSS modules) import classes from './Button.module.css'; <Button classNames={{ root: classes.button, // Outer wrapper label: classes.buttonLabel // Text content }} />
/* Button.module.css */ .button { background: linear-gradient(45deg, blue, purple); } .buttonLabel { font-weight: 700; }
// Option 2: styles prop (inline styles for inner elements) <Button styles={{ root: { padding: '10px 20px' }, label: { color: 'white' } }} /> // Option 3: CSS variables <Button style={{ '--button-bg': 'var(--mantine-color-blue-6)' }} /> // Option 4: Data attributes for state <Button data-active={isActive} />
Finding selector names: Check Mantine docs for each component's "Styles API" section listing available selectors.
Form Handling (@mantine/form)
import { useForm } from '@mantine/form'; import { TextInput, Checkbox, Button, Box } from '@mantine/core'; function LoginForm() { const form = useForm({ initialValues: { email: '', password: '', rememberMe: false, }, validate: { email: (value) => /^\S+@\S+$/.test(value) ? null : 'Invalid email', password: (value) => value.length >= 8 ? null : 'Password must be 8+ characters', }, // Optional: validate on change instead of only on submit validateInputOnChange: true, }); const handleSubmit = (values: typeof form.values) => { console.log('Form submitted:', values); }; return ( <Box component="form" onSubmit={form.onSubmit(handleSubmit)}> <TextInput label="Email" placeholder="your@email.com" {...form.getInputProps('email')} /> <TextInput label="Password" type="password" {...form.getInputProps('password')} /> <Checkbox label="Remember me" {...form.getInputProps('rememberMe', { type: 'checkbox' })} /> <Button type="submit" mt="md">Login</Button> </Box> ); }
Key form methods:
- Binds value, onChange, errorform.getInputProps('fieldName')
- For checkboxes/switchesform.getInputProps('field', { type: 'checkbox' })
- Validates before calling handlerform.onSubmit(handler)
- Programmatic updatesform.setFieldValue('field', value)
- Reset to initial valuesform.reset()
- Manual validationform.validate()
Polymorphic Components
Change the underlying HTML element:
// Button as link <Button component="a" href="/dashboard"> Go to Dashboard </Button> // Text as span (default is p) <Text component="span">Inline text</Text> // Card as article <Card component="article">Content</Card>
TypeScript note: Ref type changes with component prop!
// Default: HTMLButtonElement const buttonRef = useRef<HTMLButtonElement>(null); <Button ref={buttonRef} /> // With component="a": HTMLAnchorElement const linkRef = useRef<HTMLAnchorElement>(null); <Button component="a" ref={linkRef} href="/" />
Theming
import { MantineProvider, createTheme } from '@mantine/core'; const theme = createTheme({ primaryColor: 'violet', colors: { // Add custom color palette brand: [ '#f0e6ff', '#d9c2ff', '#c29dff', '#ab79ff', '#9454ff', '#7d30ff', '#660bff', '#5200d9', '#3e00a6', '#2b0073' ], }, components: { Button: { defaultProps: { radius: 'md', }, }, }, }); function App() { return ( <MantineProvider theme={theme}> {/* Your app */} </MantineProvider> ); }
Dark Mode
import { useMantineColorScheme, Button } from '@mantine/core'; function ColorSchemeToggle() { const { colorScheme, toggleColorScheme } = useMantineColorScheme(); return ( <Button onClick={() => toggleColorScheme()}> {colorScheme === 'dark' ? 'Light' : 'Dark'} mode </Button> ); }
CSS for dark mode:
/* Use light-dark() function */ .myComponent { background: light-dark(white, var(--mantine-color-dark-7)); color: light-dark(black, white); }
Common Pitfalls
1. Nested Interactive Elements
Wrong:
<Accordion.Control> <Button onClick={handleDelete}>Delete</Button> {/* Invalid! */} </Accordion.Control>
Correct:
<Accordion.Item> <Box style={{ display: 'flex', alignItems: 'center' }}> <Accordion.Control style={{ flex: 1 }}>Title</Accordion.Control> <Button onClick={handleDelete}>Delete</Button> </Box> <Accordion.Panel>Content</Accordion.Panel> </Accordion.Item>
2. Tooltip on Disabled Button
Wrong:
<Tooltip label="Disabled"> <Button disabled>Click me</Button> {/* Tooltip won't show! */} </Tooltip>
Correct:
<Tooltip label="Disabled"> <Button data-disabled onClick={(e) => e.preventDefault()}> Click me </Button> </Tooltip>
3. ActionIcon.Group Wrapping
Wrong:
<ActionIcon.Group> <div> {/* Invalid wrapper! */} <ActionIcon><IconEdit /></ActionIcon> </div> </ActionIcon.Group>
Correct:
<ActionIcon.Group> <ActionIcon><IconEdit /></ActionIcon> <ActionIcon><IconTrash /></ActionIcon> </ActionIcon.Group>
4. Missing aria-label
Wrong:
<ActionIcon> <IconSearch /> {/* No accessible name! */} </ActionIcon>
Correct:
<ActionIcon aria-label="Search"> <IconSearch /> </ActionIcon>
5. AspectRatio in Flexbox
Wrong:
<Flex> <AspectRatio ratio={16/9}> {/* Won't size correctly */} <Image src="/photo.jpg" /> </AspectRatio> </Flex>
Correct:
<Flex> <AspectRatio ratio={16/9} w={300}> {/* Explicit width */} <Image src="/photo.jpg" /> </AspectRatio> </Flex>
6. Select vs Autocomplete Confusion
- Select: User MUST choose from options (enforces list)
- Autocomplete: User CAN type any value (suggestions only)
// Use Select when value must be from list <Select data={['Option 1', 'Option 2']} /> // Use Autocomplete when free text is acceptable <Autocomplete data={['Suggestion 1', 'Suggestion 2']} />
Accessibility Requirements
-
Icon buttons must have aria-label:
<ActionIcon aria-label="Close modal"> <IconX /> </ActionIcon> -
Use closeButtonLabel prop:
<Modal closeButtonLabel="Close this dialog" opened={opened} onClose={close}> -
Set heading order for accordions:
<Accordion.Control order={3}> {/* Renders as <h3> */} -
Test keyboard navigation:
- Tab through form fields
- Enter/Space on buttons
- Escape to close modals
- Arrow keys in menus
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Styles not applying | Wrong selector name | Check component's Styles API docs for available selectors |
| Dark mode has wrong colors | Hardcoded color values | Use CSS function or theme colors |
| Form not validating | Wrong config | Use for submit-time, for live validation |
| TypeScript ref errors | Polymorphic component | Update ref type to match prop value |
| Component won't accept custom props | Polymorphic typing | Props don't extend default element; use to change |
| Tooltip not showing on disabled | Disabled blocks events | Use with preventDefault |
External Documentation
For latest Mantine documentation:
-
Context7 (recommended):
mcp__context7__get-library-docs context7CompatibleLibraryID: "/mantinedev/mantine" topic: "Button" or "Select" or "form" etc. -
Direct fetch:
WebFetch → https://mantine.dev/llms.txt -
Official docs: https://mantine.dev
Component Quick Reference
See REFERENCE.md for detailed component patterns including:
- Layout: Stack, Group, Grid, Flex, Container, AppShell
- Inputs: TextInput, Select, Checkbox, DatePicker
- Feedback: Modal, Notifications, Alert
- Navigation: Tabs, NavLink, Breadcrumbs
- Data: Table, Skeleton, Timeline
Related Agent
For comprehensive React + Mantine UI guidance that coordinates this and other Mantine skills, use the
agent.mantine-ui-expert
Cost Optimization: Use
model="haiku" when invoking this agent for routine component development tasks. Haiku is sufficient for template-based Mantine patterns and Styles API usage.