Chakra UI to Mantine Migration Guide — Component-by-Component
Last updated: April 2026 · 12 min read
Why Switch from Chakra UI to Mantine?
Chakra UI and Mantine are both beloved React component libraries that prioritize developer experience, but Mantine has rapidly evolved into a more feature-complete ecosystem that many teams are now choosing for new projects and migrations alike. Understanding the differences helps you decide whether a migration is worth the effort for your team.
120+ hooks and utilities. Mantine ships an enormous collection of hooks through its @mantine/hooks package. From useDisclosure and useClipboard to useIntersection and useHotkeys, these hooks cover use cases that would otherwise require third-party packages. Chakra provides fewer built-in hooks, meaning your project accumulates more dependencies over time.
Superior TypeScript developer experience. While Chakra UI offers decent TypeScript support, Mantine was built TypeScript-first from day one. Every component, every prop, and every hook is fully typed with strict generic inference. Auto-completion is more reliable, prop errors are caught earlier, and the overall DX feels significantly more polished when working in VSCode or any TypeScript-aware editor.
More components out of the box.Mantine offers over 100 components compared to Chakra’s roughly 60. This includes complex widgets like DatePicker, RichTextEditor, Spotlight (command palette), Carousel, and Notifications that Chakra does not include. Having these as first-party components means consistent theming, better integration, and fewer compatibility headaches.
CSS Modules over CSS-in-JS. Starting with v7, Mantine moved away from Emotion-based CSS-in-JS to native CSS Modules and PostCSS. This eliminates runtime style injection, improves server-side rendering performance, and produces smaller bundles. Chakra UI still relies on Emotion at runtime, which can cause hydration mismatches and performance overhead in SSR-heavy applications.
Component Mapping: Chakra UI to Mantine
Below is a detailed mapping of the most commonly used Chakra UI components and their Mantine equivalents. Each example shows the Chakra source code on the left and the corresponding Mantine code on the right. You can also use the FrontFamily Converter to automate these transformations instantly.
Button
<Button colorScheme="blue" variant="solid"> Save Changes </Button>
<Button color="blue" variant="filled"> Save Changes </Button>
Input → TextInput
<FormControl> <FormLabel>Email</FormLabel> <Input variant="outline" /> <FormHelperText>Enter email</FormHelperText> </FormControl>
<TextInput label="Email" description="Enter email" variant="default" />
Modal
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Confirm</ModalHeader>
<ModalBody>Are you sure?</ModalBody>
<ModalFooter>
<Button onClick={onClose}>Cancel</Button>
</ModalFooter>
</ModalContent>
</Modal><Modal opened={opened} onClose={close}
title="Confirm">
<Text>Are you sure?</Text>
<Group mt="md" justify="flex-end">
<Button onClick={close}>Cancel</Button>
</Group>
</Modal>Switch
<Switch
isChecked={enabled}
onChange={handleChange}
colorScheme="green"
/><Switch
checked={enabled}
onChange={handleChange}
color="green"
/>Badge
<Badge colorScheme="green">Active</Badge> <Badge variant="outline">Draft</Badge>
<Badge color="green">Active</Badge> <Badge variant="outline">Draft</Badge>
Avatar
<Avatar src={user.avatar} name={user.name} />
<Avatar name="JD" bg="blue.500" /><Avatar src={user.avatar} alt={user.name} />
<Avatar color="blue">JD</Avatar>Tabs
<Tabs>
<TabList>
<Tab>Profile</Tab>
<Tab>Settings</Tab>
</TabList>
<TabPanels>
<TabPanel>Profile content</TabPanel>
<TabPanel>Settings content</TabPanel>
</TabPanels>
</Tabs><Tabs defaultValue="profile">
<Tabs.List>
<Tabs.Tab value="profile">Profile</Tabs.Tab>
<Tabs.Tab value="settings">Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="profile">Profile content</Tabs.Panel>
<Tabs.Panel value="settings">Settings content</Tabs.Panel>
</Tabs>Select
<Select placeholder="Choose role"> <option value="admin">Admin</option> <option value="user">User</option> </Select>
<Select
placeholder="Choose role"
data={[
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' },
]}
/>Tooltip
<Tooltip label="More info" placement="top">
<IconButton icon={<InfoIcon />} />
</Tooltip><Tooltip label="More info" position="top"> <ActionIcon><IconInfoCircle /></ActionIcon> </Tooltip>
Alert
<Alert status="warning">
<AlertIcon />
<AlertDescription>
Session expiring soon.
</AlertDescription>
</Alert><Alert
color="yellow"
title="Warning"
icon={<IconAlertTriangle />}>
Session expiring soon.
</Alert>Prop Conversion Reference
Migrating from Chakra UI to Mantine involves renaming several commonly used props. Chakra uses a prefix convention (is prefix for booleans, colorScheme for color tokens) while Mantine uses more standard HTML-like prop names. Here are the most common transformations:
| Chakra Prop | Mantine Equivalent | Notes |
|---|---|---|
isDisabled | disabled | Standard HTML attribute |
isLoading | loading | Removes “is” prefix |
isOpen | opened | Past participle convention |
colorScheme="blue" | color="blue" | Shorter prop name |
variant="solid" | variant="filled" | Different naming convention |
size="lg" | size="lg" | Same size tokens |
placement="top" | position="top" | Tooltip/Popover positioning |
mt={4} | mt="md" | Named tokens instead of numbers |
Hook Migration: Chakra to Mantine
Both libraries provide utility hooks, but Mantine’s hook library is substantially larger. Here is how the most commonly used Chakra hooks map to their Mantine equivalents, along with hooks that are exclusive to Mantine:
useDisclosure (both libraries)
Both Chakra and Mantine provide useDisclosure for toggling boolean state. The API is nearly identical: both return an array or object with open, close, and toggle handlers. In Chakra, the return value uses isOpen; in Mantine, it uses opened. A simple find-and-replace handles this migration.
useToast → notifications.show
Chakra’s useToast hook returns a function that displays toast notifications. Mantine replaces this with the @mantine/notifications package, which uses a static notifications.show() call instead of a hook. This means you can trigger notifications from anywhere, including outside of React components and inside utility functions.
useClipboard (both libraries)
Both provide useClipboardwith similar APIs. Mantine’s version includes a built-in timeout parameter for automatically resetting the copied state, which is a common UX pattern that Chakra leaves to the developer.
Mantine-exclusive hooks
Mantine includes hooks that have no Chakra equivalent: useHotkeys for keyboard shortcuts, useIntersection for scroll-based visibility, useForm for form state management with validation, useLocalStorage for persistent state, and useDebouncedValue for input debouncing. These hooks can replace several third-party dependencies in your project.
Interactive Component Reference
Search any Chakra UI component to find its Mantine equivalent. Components marked with ⚠ have no direct replacement and require custom implementation.
| Chakra UI | Mantine | Props / Notes | |
|---|---|---|---|
ButtoncolorScheme, variant, isDisabled, isLoading, leftIcon | Buttoncolor, variant, disabled, loading, leftSection | variant="solid" becomes variant="filled"; isDisabled becomes disabled | |
Inputvariant, isInvalid, isDisabled, placeholder | TextInputvariant, error, disabled, placeholder, label, description | Mantine TextInput includes built-in label and description; no FormControl wrapper needed | |
Boxbg, p, mx, borderRadius, boxShadow | Boxbg, p, mx, style | Mantine Box supports fewer style props; use style prop or CSS Modules for complex styling | |
TextfontSize, color, fontWeight, noOfLines | Textsize, c, fw, lineClamp | Prop shorthand differs: fontSize becomes size, color becomes c, fontWeight becomes fw | |
ModalisOpen, onClose, size, isCentered | Modalopened, onClose, size, centered | isOpen becomes opened; requires no Overlay or Content sub-components | |
BadgecolorScheme, variant, fontSize | Badgecolor, variant, size | colorScheme becomes color; nearly identical API | |
Avatarsrc, name, size, bg | Avatarsrc, alt, size, color | Mantine Avatar uses children for initials instead of name prop | |
SwitchisChecked, onChange, colorScheme, size | Switchchecked, onChange, color, size | isChecked becomes checked; colorScheme becomes color | |
Alertstatus, variant | Alertcolor, variant, title, icon | status maps to color; Mantine Alert has built-in title and icon props | |
Selectplaceholder, value, onChange, children | Selectplaceholder, value, onChange, data | Uses data array prop instead of <option> children | |
Spinnersize, color, thickness | Loadersize, color, type | Mantine Loader supports multiple animation types: oval, bars, dots | |
Progressvalue, colorScheme, hasStripe, isAnimated | Progressvalue, color, striped, animated | hasStripe becomes striped; isAnimated becomes animated | |
Tooltiplabel, placement, hasArrow | Tooltiplabel, position, withArrow | placement becomes position; hasArrow becomes withArrow | |
Dividerorientation, variant | Dividerorientation, variant, label | Mantine Divider supports a label prop for text inside the divider | |
Tabsindex, onChange, variant, colorScheme | TabsdefaultValue, onChange, variant, color | Uses Tabs.List, Tabs.Tab, Tabs.Panel with value-based identification | |
useDisclosureisOpen, onOpen, onClose, onToggle | useDisclosureopened, open, close, toggle | isOpen becomes opened; onOpen becomes open (from @mantine/hooks) | |
useToasttitle, description, status, duration | notifications.showtitle, message, color, autoClose | Static function instead of hook; from @mantine/notifications package | |
DrawerisOpen, onClose, placement, size | Draweropened, onClose, position, size | isOpen becomes opened; placement becomes position | |
MenuisOpen, onClose, placement | Menuopened, onChange, position | Uses Menu.Target, Menu.Dropdown, Menu.Item compound components | |
AccordionallowToggle, allowMultiple, defaultIndex | AccordiondefaultValue, multiple, variant | Uses Accordion.Item, Accordion.Control, Accordion.Panel sub-components | |
NumberInputvalue, onChange, min, max, step | NumberInputvalue, onChange, min, max, step | Nearly identical API; Mantine adds increment/decrement controls by default | |
PinInputlength, onComplete, otp | PinInputlength, onComplete, oneTimeCode | otp becomes oneTimeCode; functionally identical | |
Skeletonheight, width, isLoaded, startColor | Skeletonheight, width, visible, animate | isLoaded becomes visible; color customization via CSS variables | |
TagcolorScheme, variant, size | Badgecolor, variant, size | Chakra Tag maps to Mantine Badge; no separate Tag component in Mantine | |
PopoverisOpen, onClose, placement, trigger | Popoveropened, onChange, position | Uses Popover.Target and Popover.Dropdown compound components | |
Statlabel, number, helpText | No direct equivalent | No built-in Stat component; build with Text + Group composition or use a community package | |
SimpleGridcolumns, spacing, minChildWidth | SimpleGridcols, spacing, verticalSpacing | columns becomes cols; minChildWidth uses breakpoints object instead |
What Developers Actually Hit
Based on migration reports from engineering teams. These are the problems documentation doesn’t warn you about.
Both libraries have useDisclosure, but Chakra returns { isOpen, onOpen, onClose, onToggle } (an object) while Mantine returns [opened, { open, close, toggle }] (a tuple). Different shape, different property names. A simple find-and-replace on isOpen to opened misses the destructuring pattern change, causing runtime errors that TypeScript catches only if you have strict mode enabled.
Chakra uses colorScheme="blue" for component theming. Mantine uses color="blue" but the color name mapping is not guaranteed — while Chakra’s teal and Mantine’s teal exist in both, the actual hex values at each shade level differ. Designs that depended on exact color values will look subtly wrong after a name-only migration.
Chakra’s bg, p, mx work because Chakra extends styled-system. Mantine uses bg, p, mx too (since v7) but the underlying system is different — Mantine uses CSS variables, Chakra uses Emotion runtime styles. During migration when both providers are active, both systems may generate conflicting CSS for the same property on the same element, with the winner depending on injection order.
Convert Chakra UI to Mantine instantly
Skip the manual work. Paste your Chakra UI code into the FrontFamily Converter and get production-ready Mantine output with correct imports, prop mappings, and component restructuring. A pre-loaded form example is ready for you to try.
Open Converter with Chakra → Mantine ExampleStyling Migration: Style Props to CSS Modules
The biggest paradigm shift. Chakra UI is built entirely around style props: you pass bg, p, mx, and borderRadius directly to components. Mantine v7 moved away from this approach toward CSS Modules and a dedicated style prop. While Mantine still supports some style props like mt and mb on all components, complex styling should be done through CSS Modules or the styles API.
Theme token differences. Chakra uses a numeric spacing scale where 4 maps to 1rem. Mantine uses named tokens: "xs", "sm", "md", "lg", "xl". Colors also differ: blue.500 in Chakra becomes blue.5 in Mantine (0-9 scale instead of 50-900).
Server-side rendering. Because Mantine uses CSS Modules instead of runtime CSS-in-JS, SSR is dramatically simpler. There is no need for Emotion cache configuration, no risk of hydration mismatches from style injection order, and no flash of unstyled content. This makes Mantine a particularly strong choice for Next.js applications where server components are the default.
Import Changes at a Glance
import { Button } from '@chakra-ui/react';
import { Input } from '@chakra-ui/react';
import { Modal, ModalOverlay } from '@chakra-ui/react';
import { useDisclosure } from '@chakra-ui/react';
import { useToast } from '@chakra-ui/react';import { Button } from '@mantine/core';
import { TextInput } from '@mantine/core';
import { Modal } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';