Components API changes

Tabs

Tabs and associated Prism.Tabs components now have new API. New API provides the following enhancements:

  • Tabs are now more accessible
  • Tabs content no longer unmounts on tab change, it is hidden with display: none
  • It is now easier to manage controlled tabs state with string value instead of index
  • With new component structure it is now easier to modify styles of each part with sx or classname props

Tabs component now supports the following new props:

  • radius prop (defaults to theme.defaultRadius)
  • inverted prop allows to display panels before controls
  • loop prop control arrow keys behavior (allows to go from first to last and vice versa)
  • activateTabWithKeyboard prop controls how tabs respond to arrows and Home/End key presses
  • allowTabDeactivation prop allows user to deactivate current active tab
Messages tab content
Settings tab content
Color
Variant
Radius
xs
sm
md
lg
xl
Orientation
import { Tabs } from '@mantine/core';
import { IconPhoto, IconMessageCircle, IconSettings } from '@tabler/icons';
function Demo() {
return (
<Tabs defaultValue="gallery">
<Tabs.List>
<Tabs.Tab value="gallery" icon={<IconPhoto size={14} />}>Gallery</Tabs.Tab>
<Tabs.Tab value="messages" icon={<IconMessageCircle size={14} />}>Messages</Tabs.Tab>
<Tabs.Tab value="settings" icon={<IconSettings size={14} />}>Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="gallery" pt="xs">
Gallery tab content
</Tabs.Panel>
<Tabs.Panel value="messages" pt="xs">
Messages tab content
</Tabs.Panel>
<Tabs.Panel value="settings" pt="xs">
Settings tab content
</Tabs.Panel>
</Tabs>
);
}

Accordion

Accordion component now has new API with the following new props:

  • variant prop controls visuals, Accordion now has 4 variants
  • radius prop (defaults to theme.defaultRadius) controls border-radius for all variants except default
  • loop prop control arrow keys behavior (allows to go from first to last and vice versa)
  • disabled prop allows to disable items
  • icon prop adds icon to the opposite side of chevron
Colors, fonts, shadows and many other parts are customizable to fit your design needs
Radius
xs
sm
md
lg
xl
ChevronPosition
import { Accordion } from '@mantine/core';
function Demo() {
return (
<Accordion defaultValue="customization">
<Accordion.Item value="customization">
<Accordion.Control>Customization</Accordion.Control>
<Accordion.Panel>Colors, fonts, shadows and many other parts are customizable to fit your design needs</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="flexibility">
<Accordion.Control>Flexibility</Accordion.Control>
<Accordion.Panel>Configure components appearance and behavior with vast amount of settings or overwrite any part of component styles</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="focus-ring">
<Accordion.Control>No annoying focus ring</Accordion.Control>
<Accordion.Panel>With new :focus-visible pseudo-class focus ring appears only when user navigates with keyboard</Accordion.Panel>
</Accordion.Item>
</Accordion>
);
}

Tooltip

Tooltip now requires children to be an element or a component, string, numbers, fragments and multiple elements are no longer supported. In addition to that Tooltip no longer wraps target element with div tag, events are added directly to target element.

import { Tooltip, Badge } from '@mantine/core';
function Demo() {
return (
<>
<Tooltip label="OK">
<button>Native button – ok</button>
</Tooltip>
<Tooltip label="OK">
<Badge>Mantine component – ok</Badge>
</Tooltip>
<Tooltip label="Throws">Raw string, NOT OK – will throw error</Tooltip>
{/* Number, NOT OK – will throw error */}
<Tooltip label="Throws">{2}</Tooltip>
<Tooltip label="Throws">
<>Fragment, NOT OK, will throw error</>
</Tooltip>
<Tooltip label="Throws">
<div>More that one node</div>
<div>NOT OK, will throw error</div>
</Tooltip>
</>
);
}

Popover

Popover component now has new API with the following breaking changes:

  • placement prop is no longer supported, Popover side and alignment is now controlled with position prop
  • Default value for trapFocus and withinPortal props is now false
  • Close button and title are no longer supported, if you need these parts – add them on your side in Popover.Dropdown component

Popover now supports the following new features:

  • Uncontrolled and controlled mode
  • width="target" prop will make popover width the same as target element
  • Popover.Dropdown can now be styled with system props (sx, className, padding props, etc.)
import { Popover, Text, Button } from '@mantine/core';
function Demo() {
return (
<Popover width={200} position="bottom" withArrow shadow="md">
<Popover.Target>
<Button>Toggle popover</Button>
</Popover.Target>
<Popover.Dropdown>
<Text size="sm">This is uncontrolled popover, it is opened when button is clicked</Text>
</Popover.Dropdown>
</Popover>
);
}

Menu

Menu component now uses Popover component under the hood and thus its API was changed in the same way:

  • Menu no longer provides default control, it should now be added with Menu.Target
  • Menu.Item component should now be used within Menu.Dropdown component
  • trapFocus prop was removed – now it is managed automatically based on trigger prop
  • closeOnScroll prop was removed – if you need this feature you will need to implement this logic on your side
import { Menu, Button, Text } from '@mantine/core';
import { IconSettings, IconSearch, IconPhoto, IconMessageCircle, IconTrash, IconArrowsLeftRight } from '@tabler/icons';
function Demo() {
return (
<Menu shadow="md" width={200}>
<Menu.Target>
<Button>Toggle menu</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Application</Menu.Label>
<Menu.Item icon={<IconSettings size={14} />}>Settings</Menu.Item>
<Menu.Item icon={<IconMessageCircle size={14} />}>Messages</Menu.Item>
<Menu.Item icon={<IconPhoto size={14} />}>Gallery</Menu.Item>
<Menu.Item
icon={<IconSearch size={14} />}
rightSection={<Text size="xs" color="dimmed">K</Text>}
>
Search
</Menu.Item>
<Menu.Divider />
<Menu.Label>Danger zone</Menu.Label>
<Menu.Item icon={<IconArrowsLeftRight size={14} />}>Transfer my data</Menu.Item>,
<Menu.Item color="red" icon={<IconTrash size={14} />}>Delete my account</Menu.Item>
</Menu.Dropdown>
</Menu>
);
}

Avatar

AvatarsGroup component is no longer exported from @mantine/core package, instead you can now use Avatar.Group component which can be combined with Tooltip or Popover to display additional information:

+5
import { Avatar } from '@mantine/core';
function Demo() {
return (
<Avatar.Group spacing="sm">
<Avatar src="image.png" radius="xl" />
<Avatar src="image.png" radius="xl" />
<Avatar src="image.png" radius="xl" />
<Avatar radius="xl">+5</Avatar>
</Avatar.Group>
);
}

InputWrapper

InputWrapper component is no longer exported from @mantine/core package, instead you can now use Input.Wrapper component:

Please enter your credit card information, we need some money
Size
xs
sm
md
lg
xl
import { Input } from '@mantine/core';
function Demo() {
return (
<Input.Wrapper
id="input-demo"
required
label="Credit card information"
description="Please enter your credit card information, we need some money"
error="Your credit card expired"
>
<Input id="input-demo" placeholder="Your email" />
</Input.Wrapper>
);
}

Dropzone

Dropzone component was migrated to context, it no longer supports function as children. Instead, you can use Dropzone.Accept, Dropzone.Reject and Dropzone.Idle components to display content based on current status.

Other Dropzone changes:

  • FullScreenDropzone component is no loner exported from the @mantine/dropzone package, use Dropzone.FullScreen component instead
  • Dropzone.FullScreen now supports all props from Dropzone component
  • Dropzone now uses data-* attributes instead of classes to change styles of root element based on current status
  • Dropzone and Dropzone.FullScreen components now supports the following new props: maxFiles, autoFocus, activateOnClick, activateOnDrag, activateOnKeyboard, dragEventsBubbling, onDragEnter, onDragLeave, onDragOver, onFileDialogCancel, onFileDialogOpen, preventDropOnDocument
import { Group, Text, useMantineTheme } from '@mantine/core';
import { IconUpload, IconPhoto, IconX } from '@tabler/icons';
import { Dropzone, DropzoneProps, IMAGE_MIME_TYPE } from '@mantine/dropzone';
export function BaseDemo(props: Partial<DropzoneProps>) {
const theme = useMantineTheme();
return (
<Dropzone
onDrop={(files) => console.log('accepted files', files)}
onReject={(files) => console.log('rejected files', files)}
maxSize={3 * 1024 ** 2}
accept={IMAGE_MIME_TYPE}
{...props}
>
<Group position="center" spacing="xl" style={{ minHeight: 220, pointerEvents: 'none' }}>
<Dropzone.Accept>
<IconUpload
size={50}
stroke={1.5}
color={theme.colors[theme.primaryColor][theme.colorScheme === 'dark' ? 4 : 6]}
/>
</Dropzone.Accept>
<Dropzone.Reject>
<IconX
size={50}
stroke={1.5}
color={theme.colors.red[theme.colorScheme === 'dark' ? 4 : 6]}
/>
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto size={50} stroke={1.5} />
</Dropzone.Idle>
<div>
<Text size="xl" inline>
Drag images here or click to select files
</Text>
<Text size="sm" color="dimmed" inline mt={7}>
Attach as many files as you like, each file should not exceed 5mb
</Text>
</div>
</Group>
</Dropzone>
);
}

Migration to Floating UI

All components that have dropdowns (DatePicker, Popover, Select, etc.) were migrated to Floating UI from popper.js:

  • position and placement props were merged into position prop, for example, position="top-start"
  • Popper component is no longer exported from @mantine/core package

MantineProvider changes

defaultProps, styles and classNames props

MantineProvider no longer supports styles, classNames and defaultProps props. Instead of separate props these values should be added to the theme. This change allows to store all components in one object and share it across multiple environments. For example, it is now much easier to share theme between application and Storybook:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider
theme={{
components: {
Tabs: {
defaultProps: { color: 'red' },
classNames: { root: 'tabs-root' },
styles: (theme) => ({
tab: {
'&[data-active]': { backgroundColor: theme.colors.red[5] },
},
}),
},
},
}}
>
<App />
</MantineProvider>
);
}

emotionCache prop

MantineProvider no longer supports emotionOptions prop, instead you will need to create emotion cache on your side and provide it with emotionCache prop. This change was made to enable custom cache to be used during ssr and support more options for emotion usage, for example with shadow dom or with iframe.

import { MantineProvider, createEmotionCache } from '@mantine/core';
const myCache = createEmotionCache({ key: 'mantine' });
function Demo() {
return (
<MantineProvider emotionCache={myCache} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
);
}

Emotion packages as peer dependencies

@emotion/react and @emotion/server packages are now not installed automatically (see related issue) – you will need to install them manually:

yarn add @emotion/react @emotion/server

Styles API changes

data- attributes

Most of components state were migrated to data- attributes. This allows to override styles more predictably without using !important and reduces complexity of components Styles API.

Mo
Tu
We
Th
Fr
Sa
Su

Inputs styles API

You can use Input and Input.Wrapper Styles API on MantineProvider to add styles to all Inputs:

Description below the input
Description below the input

Polymorphic components changes

Because of internal changes polymorphic components props types exported from @mantine/core package are no longer generic types. Now if you want to extend these types you need to provide associated element types on your side. You can find updated polymorphic components guide here.

import type { ButtonProps } from '@mantine/core';
// Previously, no longer supported
type MyButtonProps = ButtonProps<'button'> & { label: string };
// Convert to
type MyButtonProps = ButtonProps & React.ComponentPropsWithoutRef<'button'> & { label: string };

@mantine/form changes

use-form no longer exports formList function, you can now manage lists with just regular arrays. Other changes:

  • You can now use objects and lists with any level of nesting
  • useForm hook now supports clearInputErrorOnChange option to disable error clearing when input value changes and validateInputOnChange option that adds support for live fields validation
  • form.onSubmit handler now accepts second argument – a function that will be called with errors object when validation fails
  • form.addListItem was renamed to form.insertListItem, it now supports inserting items add given index
  • schema option was merged with validate option

Other breaking changes

  • Select and MultiSelect component now require returning created item from onCreate handler
  • Portal component no longer accepts position and zIndex props – it is now required to add these styles to Portal children
  • Modal component no longer supports size="full", use size="100%" instead
  • FloatingTooltip component was renamed to Tooltip.Floating
  • Most components with dropdowns (Tooltip, Popover, ColorPicker, DatePicker, Select, etc.) are no longer using Portal by default, it is now required to set withinPortal if you need this feature
  • Input no longer supports headless variant, use unstyled prop instead
  • AppShell fixed prop is now true by default
  • CheckboxGroup, RadioGroup and Chips components are no longer exported from @mantine/core, use Checkbox.Group, Radio.Group and Chip.Group components instead
  • @mantine/hooks package no longer exports old use-form hook, use @mantine/form package instead
  • Group component no longer supports direction prop, use Stack component instead for vertical stacks
  • use-uncontrolled hook logic was changed, it no longer supports rule parameter
  • use-id hook now supports React 18 useId hook with a fallback for older React versions, generateId function is no longer supported
  • @mantine/hooks package no longer exports useBooleanToggle hook, use useDisclosure hook instead
  • use-toggle hook API was changed, it no longer accepts initial value as first argument
  • use-intersection hook API was changed to keep API consistent across all hooks
  • use-focus-return hook no longer supports transitionDuration prop due to changes in use-focus-trap hook
  • use-notifications hook from @mantine/notifications package no longer has showNotification, hideNotification and other functions, use separate functions exported from the package for that
  • id prop in Modals manager was renamed to modalId due to React 18 issues
  • Button component no longer provides separate classes for variants

@mantine/carousel package

New @mantine/carousel package based on embla carousel:

@mantine/nprogress package

New @mantine/nprogress package displays navigation progress bar at the top of the page, it can be easily integrated with Next.js and other similar frameworks:

import { Button, Group } from '@mantine/core';
import {
NavigationProgress,
incrementNavigationProgress,
decrementNavigationProgress,
setNavigationProgress,
startNavigationProgress,
stopNavigationProgress,
resetNavigationProgress,
} from '@mantine/nprogress';
function Demo() {
return (
<>
<NavigationProgress />
<Group position="center">
<Button onClick={() => incrementNavigationProgress(10)}>Add 10%</Button>
<Button color="red" onClick={() => decrementNavigationProgress(10)}>
Decrease 10%
</Button>
<Button onClick={() => setNavigationProgress(50)}>Set 50%</Button>
<Button onClick={() => startNavigationProgress()}>Start</Button>
<Button onClick={() => stopNavigationProgress()}>Stop</Button>
<Button onClick={() => resetNavigationProgress()}>Reset</Button>
</Group>
</>
);
}

React 18 support

All Mantine components now support React 18, all known issues related to React 18 migration were fixed:

  • ColorPicker and ColorInput components no longer throw error on value change
  • Issue with stale Dropzone status was fixed
  • Multiple issues with types were fixed (mostly related to children prop changes)
  • The entire Mantine codebase was migrated to React 18 (documentation website, Mantine UI, all packages)

Unstyled components

All components now support unstyled prop which removes all non-essential Mantine styles from the component. This is useful when you want to style some component from scratch without overwriting any styles.

Unstyled Tabs:

Chat panel
Account panel

Unstyled Accordion:

New theme properties

activeStyles

theme.activeStyles lets you override styles added to buttons with :active pseudo-class:

import { Button, MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider theme={{ activeStyles: { transform: 'scale(0.95)' } }}>
<Button>Press me</Button>
</MantineProvider>
);
}

fontWeight for each heading

theme.headings now has an option to set fontWeight for each heading individually:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider
theme={{
headings: {
// font-weight for all headings
fontWeight: 400,
sizes: {
// Overrides individual headings
h1: { fontWeight: 100 },
h6: { fontWeight: 900 },
},
},
}}
>
<App />
</MantineProvider>
);
}

defaultGradient

theme.defaultGradient defines default gradient value for components that support variant="gradient" (Button, ThemeIcon, etc.):

respectReduceMotion

theme.respectReduceMotion allows to disregard user OS settings and play animations as usual:

cursorType

theme.cursorType determines which cursor type will native controls have. If it is set to pointer then Checkbox, Radio, NativeSelect and other native elements will have cursor: pointer style.

New components

NavLink component

New NavLink component:

HoverCard component

New HoverCard component:

CopyButton component

New CopyButton component:

FileInput component

New FileInput component:

import { FileInput } from '@mantine/core';
function Demo() {
return <FileInput label="Upload files" placeholder="Upload files" accept="image/png,image/jpeg" />;
}

FileButton component

New FileButton component:

FocusTrap component

New FocusTrap component:

New features

ScrollArea.Autosize component

ScrollArea.Autosize component lets you use ScrollArea with maxHeight:

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta perspiciatis reiciendis voluptate eaque itaque quos. Natus iure tenetur libero, reprehenderit ad, sequi, in aliquam eos necessitatibus expedita delectus veniam culpa!

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta perspiciatis reiciendis voluptate eaque itaque quos. Natus iure tenetur libero, reprehenderit ad, sequi, in aliquam eos necessitatibus expedita delectus veniam culpa!

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta perspiciatis reiciendis voluptate eaque itaque quos. Natus iure tenetur libero, reprehenderit ad, sequi, in aliquam eos necessitatibus expedita delectus veniam culpa!

import { useCounter } from '@mantine/hooks';
import { ScrollArea, Button, Group } from '@mantine/core';
const lorem =
'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta perspiciatis reiciendis voluptate eaque itaque quos. Natus iure tenetur libero, reprehenderit ad, sequi, in aliquam eos necessitatibus expedita delectus veniam culpa!';
function Demo() {
const [count, handlers] = useCounter(3, { min: 0, max: 10 });
const content = Array(count)
.fill(0)
.map((_, index) => <p key={index}>{lorem}</p>);
return (
<>
<ScrollArea.Autosize maxHeight={300} sx={{ maxWidth: 400 }} mx="auto">
{content}
</ScrollArea.Autosize>
<Group position="center" mt="md">
<Button variant="outline" color="red" onClick={handlers.decrement}>
Remove paragraph
</Button>
<Button variant="outline" onClick={handlers.increment}>
Add paragraph
</Button>
</Group>
</>
);
}

Tooltip delay group

Tooltip.Group component can be used to sync open and close delays for multiple tooltips:

import { Tooltip, Button, Group } from '@mantine/core';
function Demo() {
return (
<Tooltip.Group openDelay={500} closeDelay={100}>
<Group position="center">
<Tooltip label="Tooltip 1">
<Button variant="outline">Button 1</Button>
</Tooltip>
<Tooltip label="Tooltip 2">
<Button variant="outline">Button 2</Button>
</Tooltip>
<Tooltip label="Tooltip 3">
<Button variant="outline">Button 3</Button>
</Tooltip>
</Group>
</Tooltip.Group>
);
}

Button.Group component

Button.Group merges borders of adjacent buttons:

Orientation
import { Button } from '@mantine/core';
function Demo() {
return (
<Button.Group>
<Button variant="default">First</Button>
<Button variant="default">Second</Button>
<Button variant="default">Third</Button>
</Button.Group>
);
}

Fullscreen Modal

Modal component now supports fullScreen prop:

Input.Wrapper inputContainer prop

All inputs that use Input.Wrapper component under the hood (TextInput, Autocomplete, DatePicker, etc.) now support inputContainer prop. This prop let you add additional elements before/after input element or add floating elements that will be positioned relative to the input. Example with Tooltip:

Tooltip will be relative to the input
import { useState } from 'react';
import { TextInput, Tooltip } from '@mantine/core';
function Demo() {
const [focused, setFocused] = useState(false);
return (
<TextInput
label="TextInput with tooltip"
description="Tooltip will be relative to the input"
placeholder="Focus me to see tooltip"
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
inputContainer={(children) => (
<Tooltip label="Additional information" position="top-start" opened={focused}>
{children}
</Tooltip>
)}
/>
);
}

Input.Wrapper inputWrapperOrder prop

New inputWrapperOrder prop allows to define the order of Input.Wrapper parts:

Description below the input
Error and description are
import { TextInput } from '@mantine/core';
function Demo() {
return (
<>
<TextInput
label="Custom layout"
placeholder="Custom layout"
description="Description below the input"
inputWrapperOrder={['label', 'error', 'input', 'description']}
/>
<TextInput
mt="xl"
label="Custom layout"
placeholder="Custom layout"
description="Error and description are"
error="both below the input"
inputWrapperOrder={['label', 'input', 'description', 'error']}
/>
</>
);
}

Input.Label, Input.Error and Input.Description

Input component now exposes Input.Label, Input.Error and Input.Description, that were previously the parts of InputWrapper component. You can use these components to create custom form layouts if default Input.Wrapper layout does not fit your requirements:

Input description
import { Input } from '@mantine/core';
function Demo() {
return (
<>
<Input.Label required>Input label</Input.Label>
<Input.Description>Input description</Input.Description>
<Input.Error>Input error</Input.Error>
</>
);
}

Card.Section improvements

Card.Section now supports the following props to simplify customizations:

  • withBorder prop will add top and bottom border to Card.Section depending on its position relative to other content and sections
  • inheritPadding prop will add the same left and right padding to Card.Section as set in Card component
Review pictures
200+ images uploaded since last visit, review them to select which one should be added to your gallery

Slider thumbSize

Slider and RangeSlider components now support thumbSize prop to configure thumbs width and height from prop:

import { Slider, RangeSlider } from '@mantine/core';
function Demo() {
return (
<>
<Slider thumbSize={14} defaultValue={20} />
<RangeSlider thumbSize={14} mt="xl" defaultValue={[20, 80]} />
</>
);
}

New hooks

Other changes

  • Affix now supports withinPortal prop
  • Burger now supports transitionDuration prop
  • Collapse now support ref prop
  • NumberInput has new increment/decrement controls
  • ThemeIcon now support any CSS color value in color prop
  • Text now supports numbers in size prop to set size in px
  • RichTextEditor now uses tabler icons instead of Radix icons
  • LoadingOverlay now supports overlayBlur prop
  • Slider now supports Home and End keys
  • Modals manager now supports event based functions, it is now the primary way to work with the package
  • Prism now supports radius prop
  • DatePicker now supports modalProps to spread props to inner Modal component
  • Anchor and Text components will now inherit font-size from parent if size prop is not set
  • ScrollArea now supports type="never" to hide scrollbars

Documentation updates