Version 4.0.0

Release date

Mantine UI

Mantine UI is a new project with set of more than 120 responsive components built with Mantine. All components support dark/light color scheme and Mantine theme customizations. Mantine UI is free for everyone.

Breaking changes

  • @mantine/core package no longer exports CONTAINER_SIZES variable
  • Prism now trims code by default, to disable that set <Prism trim={false} />
  • useForm hook exported from @mantine/hooks package is now deprecated, it will be removed in one of the next releases.
  • @mantine/eslint-config was migrated to eslint-config-mantine

Renamed props

Some props were renamed to make Mantine components more consistent:

  • Dialog, Card, Paper, Header and Navbar
    • paddingp
  • Container
    • paddingpx
  • Radio
    • childrenlabel
  • RadioGroup:
    • variantorientation
  • Tooltip:
    • delaycloseDelay
  • Popover:
    • noClickOutsidecloseOnClickOutside
    • noFocusTraptrapFocus
    • noEscapecloseOnEscape
  • Modal:
    • noFocusTraptrapFocus
    • hideCloseButtonwithCloseButton
  • Drawer:
    • noFocusTraptrapFocus
    • hideCloseButtonwithCloseButton
    • noOverlaywithOverlay
    • noCloseOnEscapecloseOnEscape
    • noCloseOnClickOutsidecloseOnClickOutside
    • noScrollLocklockScroll

Default props on MantineProvider

Most of components now support default props on MantineProvider:

import { MantineProvider, Button } from '@mantine/core';
function App() {
return (
<MantineProvider
defaultProps={{
Button: { color: 'red' },
Badge: { size: 'xl', radius: 0 },
// ... default props for other components
}}
>
{/* By default, Button will have red color */}
<Button>Red button</Button>
{/* Default color can be overwritten by props */}
<Button color="blue">Blue button</Button>
{/* By default, Badge will have xl size and 0 radius */}
<Badge>Badge</Badge>
</MantineProvider>
);
}

Styles params on MantineProvider

You can now get component styles params in MantineProvider styles prop. Each component that has Styles API now exports type that can be assigned to params ComponentNameStylesParams, for example, ButtonStylesParams. This feature can be used to add more complex context styles that were not possible before:

import { MantineProvider, ButtonStylesParams } from '@mantine/core';
function Demo() {
return (
<MantineProvider
styles={{
Button: (theme, params: ButtonStylesParams) => ({
root: {
// use params to calculate dynamic styles
color: theme.colors[params.color || theme.primaryColor][1],
padding: params.size === 'lg' ? '15px 45px' : undefined,
},
}),
}}
/>
);
}

Nested MantineProvider inheritance

Nested MantineProviders will now inherit theme override, emotionOptions, defaultProps and styles from parent provider if inherit prop is set:

import { MantineProvider, Button } from '@mantine/core';
function App() {
return (
// Parent MantineProvider
<MantineProvider
theme={{ colorScheme: 'dark' }}
styles={{ Button: { root: { fontWeight: 400 } } }}
defaultProps={{ Badge: { variant: 'outline' } }}
emotionOptions={{ key: 'custom-cache' }}
>
<Button>Affected only by parent provider</Button>
{/*
Child MantineProvider, inherits theme, emotionOptions, defaultProps and styles
from parent MantineProvider. Other properties specified on child provider will override parent props.
For example, theme override will be: { colorScheme: 'dark', primaryColor: 'red' }
*/}
<MantineProvider theme={{ primaryColor: 'red' }} inherit>
<Button>Affected only by child provider</Button>
</MantineProvider>
</MantineProvider>
);
}

Default radius and focus ring configuration on theme

Mantine theme now includes two new properties: defaultRadius and focusRing.

defaultRadius property is used to set border-radius on most components by default:

import { MantineProvider, Button } from '@mantine/core';
function App() {
return (
<MantineProvider theme={{ defaultRadius: 0 }}>
<Button>Zero radius button</Button>
<Button radius="xl">xl radius button</Button>
</MantineProvider>
);
}

With focusRing property you can configure how focus ring is displayed:

  • auto – display focus ring only when user navigates with keyboard (default)
  • always – display focus ring when user navigates with keyboard and mouse
  • never – focus ring is always hidden (not recommended)
import { MantineProvider, Button } from '@mantine/core';
function App() {
return (
<MantineProvider theme={{ focusRing: 'always' }}>
<Button>Focus ring will be displayed when user clicks the button</Button>
</MantineProvider>
);
}

Padding props

All components now support setting following props to control padding:

  • p – sets padding property on root element
  • py – sets padding-top and padding-bottom properties on root element
  • px – sets padding-right and padding-left properties on root element
  • pt – sets padding-top property on root element
  • pb – sets padding-bottom property on root element
  • pl – sets padding-left property on root element
  • pr – sets padding-right property on root element
import { Paper, Container } from '@mantine/core';
function Demo() {
return (
<>
<Paper p={20} />
<Container px="xl" />
</>
);
}

createStyles references changes

createStyles function now works differently with references. Instead of generating unique identifiers with each getRef call it returns the same value for given argument:

// before 4.0.0
// getRef('icon') !== getRef('icon')
createStyles((theme, params, getRef) => {
const icon = getRef('icon');
return {
icon: { ref: icon },
parent: {
[`& .${icon}`]: { color: 'red' },
},
};
});
// in 4.0.0
// getRef('icon') === getRef('icon')
createStyles((theme, params, getRef) => ({
icon: { ref: getRef('icon') },
parent: {
[`& .${getRef('icon')}`]: { color: 'red' },
},
}));

@mantine/form package

New @mantine/form package is an enhanced version of useForm hook that was previously exported from @mantine/hooks package. @mantine/form introduces the following features:

  • Improved fields validation logic
  • Schema based validation with zod, yup or joi
  • Array fields support
import { TextInput, Checkbox, Button, Group, Box } from '@mantine/core';
import { useForm } from '@mantine/form';
function Demo() {
const form = useForm({
initialValues: {
email: '',
termsOfService: false,
},
validate: {
email: (value) => (/^\S+@\S+$/.test(value) ? null : 'Invalid email'),
},
});
return (
<Box sx={{ maxWidth: 300 }} mx="auto">
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
required
label="Email"
placeholder="your@email.com"
{...form.getInputProps('email')}
/>
<Checkbox
mt="md"
label="I agree to sell my privacy"
{...form.getInputProps('termsOfService', { type: 'checkbox' })}
/>
<Group position="right" mt="md">
<Button type="submit">Submit</Button>
</Group>
</form>
</Box>
);
}

@mantine/spotlight package

@mantine/spotlight is a new package that lets you create a command center for you application. It can be triggered with keyboard shortcut and programmatically from anywhere in you application:

import { Button, Group } from '@mantine/core';
import { SpotlightProvider, openSpotlight } from '@mantine/spotlight';
import type { SpotlightAction } from '@mantine/spotlight';
import { Home, Dashboard, FileText, Search } from 'tabler-icons-react';
function SpotlightControl() {
return (
<Group position="center">
<Button onClick={openSpotlight}>Open spotlight</Button>
</Group>
);
}
const actions: SpotlightAction[] = [
{
title: 'Home',
description: 'Get to home page',
onTrigger: () => console.log('Home'),
icon: <Home size={18} />,
},
{
title: 'Dashboard',
description: 'Get full information about current system status',
onTrigger: () => console.log('Dashboard'),
icon: <Dashboard size={18} />,
},
{
title: 'Documentation',
description: 'Visit documentation to lean more about all features',
onTrigger: () => console.log('Documentation'),
icon: <FileText size={18} />,
},
];
function Demo() {
return (
<SpotlightProvider
actions={actions}
searchIcon={<Search size={18} />}
searchPlaceholder="Search..."
shortcut="mod + shift + 1"
nothingFoundMessage="Nothing found..."
>
<SpotlightControl />
</SpotlightProvider>
);
}

New components

AspectRatio

New AspectRatio component

import { AspectRatio } from '@mantine/core';
function Demo() {
return (
<AspectRatio ratio={16 / 9}>
<iframe
src="https://www.youtube.com/embed/Dorf8i6lCuk"
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</AspectRatio>
);
}

CheckboxGroup

New CheckboxGroup component

Select your favorite framework/library
This is anonymous
Color
Orientation
Spacing
xs
sm
md
lg
xl
Size
xs
sm
md
lg
xl
import { CheckboxGroup, Checkbox } from '@mantine/core';
function Demo() {
return (
<CheckboxGroup
defaultValue={['react']}
label="Select your favorite framework/library"
description="This is anonymous"
required
>
<Checkbox value="react" label="React" />
<Checkbox value="svelte" label="Svelte" />
<Checkbox value="ng" label="Angular" />
<Checkbox value="vue" label="Vue" />
</CheckboxGroup>
);
}

BackgroundImage

New BackgroundImage component

BackgroundImage component can be used to add any content on image. It is useful for hero headers and other similar sections
Radius
xs
sm
md
lg
xl
import { BackgroundImage, Center, Text, Box } from '@mantine/core';
function Demo() {
return (
<Box sx={{ maxWidth: 300 }} mx="auto">
<BackgroundImage
src="https://images.unsplash.com/photo-1419242902214-272b3f66ee7a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=720&q=80"
radius="sm"
>
<Center p="md">
<Text color="#fff">
BackgroundImage component can be used to add any content on image. It is useful for hero
headers and other similar sections
</Text>
</Center>
</BackgroundImage>
</Box>
);
}

New features

NumberInput component now supports formatter and parser props to customize how value is displayed in the input:

import { NumberInput } from '@mantine/core';
function Demo() {
return (
<NumberInput
label="Price"
defaultValue={1000}
parser={(value) => value.replace(/\$\s?|(,*)/g, '')}
formatter={(value) =>
!Number.isNaN(parseFloat(value))
? `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
: '$ '
}
/>
);
}

Tooltip component now supports openDelay:

import { Button, Tooltip } from '@mantine/core';
function Demo() {
return (
<>
<Tooltip label="Opened after 500ms" openDelay={500}>
<Button variant="outline">Delay open - 500ms</Button>
</Tooltip>
<Tooltip label="Closes after 500ms" closeDelay={500}>
<Button variant="outline">Delay close - 500ms</Button>
</Tooltip>
</>
);
};

Slider and RangeSlider components now support onChangeEnd prop:

onChange value: 50
onChangeEnd value: 50
import { useState } from 'react';
import { Slider, Text, Container } from '@mantine/core';
function Demo() {
const [value, setValue] = useState(50);
const [endValue, setEndValue] = useState(50);
return (
<Container size={400}>
<Slider value={value} onChange={setValue} onChangeEnd={setEndValue} />
<Text mt="md" size="sm">
onChange value: <b>{value}</b>
</Text>
<Text mt={5} size="sm">
onChangeEnd value: <b>{endValue}</b>
</Text>
</Container>
);
}

Overlay component now supports blur:

Overlay with a blur.
import { useState } from 'react';
import { Button, Group, Box, Overlay } from '@mantine/core';
function Demo() {
const [visible, setVisible] = useState(false);
return (
<>
<Box sx={{ height: 100, position: 'relative' }}>
{visible && <Overlay opacity={0.6} color="#000" blur={2} />}
Overlay with a blur
</Box>
<Group position="center">
<Button onClick={() => setVisible((v) => !v)}>Toggle overlay</Button>
</Group>
</>
);
}

Other changes

  • New use-disclosure hook
  • Text component now inherits color from parent element
  • Input component now handles required prop differently to support native browser validation
  • RichTextEditor now supports providing extra quill modules via modules prop
  • DateRangePicker now displays first selected date
  • RangeCalendar now calls onChange with first selected date
  • SegmentedControl component now supports vertical orientation and disabled state
  • ThemeIcon component now supports outline variant
  • Text, Anchor and Highlight components now support underline prop
  • Container component now supports sizes configuration with default props on MantineProvider
  • All components now support negative margins for theme values with margin props (m, mx, my, mt, etc.): <Button mx="-xl">Negative margins</Button>
  • onCancel callback in @mantine/modals is now also called when confirm modal is closed without confirmation
  • New OptionalPortal component can be used to switch between rendering within Portal or as a regular child with withinPortal prop
  • Modal and Drawer can now be used without Portal
  • Title component now inherits color from parent element

3.6.0 – 4.0.0 bug fixes

  • Fix incorrect white space handling in Progress component with labels
  • Fix incorrect transform prop type in Text and associated components
  • Add missing ref type in Navbar component
  • Hidden inputs were removed from Select and MultiSelect components to prevent issues with popular form libraries
  • Fix incorrect am/pm input handling in TimeInput for non qwerty keyboards
  • Fix incorrect initial value in use-hash hook
  • Fix incorrect events handling in use-hotkeys hook for input, textarea and select elements
  • Improve TypeScript performance for polymorphic components (~ 2x increase in compilation time)
  • Fix incorrect RichTextEditor white space handling in Firefox
  • Add additional filtering to Group and MediaQuery children to avoid error when components are used with elements that do not support props (numbers, string, fragments)
  • Fix incorrect modal size for multiple months in DatePicker and DateRangePicker components
  • Add missing right and bottom padding to AppShell component
  • Fix initialLevel prop not working in DateRangePicker component
  • Add correct input mode to NumberInput – mobile devices will display correct keyboard now
  • Fix findDomNode warning in @mantine/notifications while using strict react mode