View changelog with demos on mantine.dev website
@mantine/charts
New @mantine/charts package provides a set of components
to build charts and graphs. All components are based on recharts.
Currently, the package provides AreaChart, BarChart,
LineChart and Sparkline components.
More components will be added in the next minor releases.
AreaChart component
New AreaChart component:
import { AreaChart } from '@mantine/charts';
import { data } from './data';
function Demo() {
return (
<AreaChart
h={300}
data={data}
dataKey="date"
type="stacked"
series={[
{ name: 'Apples', color: 'indigo.6' },
{ name: 'Oranges', color: 'blue.6' },
{ name: 'Tomatoes', color: 'teal.6' },
]}
/>
);
}
LineChart component
New LineChart component:
import { LineChart } from '@mantine/charts';
import { data } from './data';
function Demo() {
return (
<LineChart
h={300}
data={data}
dataKey="date"
withLegend
series={[
{ name: 'Apples', color: 'indigo.6' },
{ name: 'Oranges', color: 'blue.6' },
{ name: 'Tomatoes', color: 'teal.6' },
]}
/>
);
}
BarChart component
New BarChart component:
import { BarChart } from '@mantine/charts';
import { data } from './data';
function Demo() {
return (
<BarChart
h={300}
data={data}
dataKey="month"
type="stacked"
orientation="vertical"
yAxisProps={{ width: 80 }}
series={[
{ name: 'Smartphones', color: 'violet.6' },
{ name: 'Laptops', color: 'blue.6' },
{ name: 'Tablets', color: 'teal.6' },
]}
/>
);
}
Sparkline component
New Sparkline component:
import { Sparkline } from '@mantine/charts';
function Demo() {
return (
<Sparkline
w={200}
h={60}
data={[10, 20, 40, 20, 40, 10, 50]}
curveType="linear"
color="blue"
fillOpacity={0.6}
strokeWidth={2}
/>
);
}
OKLCH colors support
You can now use OKLCH colors in theme.colors
.
OKLCH color model has 88.18% browser support,
it is supported in all modern browsers. OKLCH model provides 30% more colors than HSL model and
has several other advantages.
Example of adding OKLCH color to the theme:
import { Button, createTheme, Group, MantineProvider } from '@mantine/core';
const theme = createTheme({
colors: {
'oklch-blue': [
'oklch(96.27% 0.0217 238.66)',
'oklch(92.66% 0.0429 240.01)',
'oklch(86.02% 0.0827 241.66)',
'oklch(78.2% 0.13 243.83)',
'oklch(71.8% 0.1686 246.06)',
'oklch(66.89% 0.1986 248.32)',
'oklch(62.59% 0.2247 250.29)',
'oklch(58.56% 0.2209 251.26)',
'oklch(54.26% 0.2067 251.67)',
'oklch(49.72% 0.1888 251.59)',
],
},
});
function Demo() {
return (
<MantineProvider theme={theme}>
<Group>
<Button color="oklch-blue">Filled</Button>
<Button color="oklch-blue" variant="outline">
Outline
</Button>
<Button color="oklch-blue" variant="light">
Light
</Button>
</Group>
</MantineProvider>
);
}
autoContrast
New theme.autoContrast
property controls whether text color should be changed based on the given color
prop
in the following components:
- ActionIcon with
variant="filled"
only - Alert with
variant="filled"
only - Avatar with
variant="filled"
only - Badge with
variant="filled"
only - Button with
variant="filled"
only - Chip with
variant="filled"
only - NavLink with
variant="filled"
only - ThemeIcon with
variant="filled"
only - Checkbox with
variant="filled"
only - Radio with
variant="filled"
only - Tabs with
variant="pills"
only - SegmentedControl
- Stepper
- Pagination
- Progress
- Indicator
- Timeline
- Spotlight
- All @mantine/dates components that are based on Calendar component
autoContrast
can be set globally on the theme level or individually for each component via autoContrast
prop,
except for Spotlight and @mantine/dates components, which only support global theme setting.
import { Button, Code, Group } from '@mantine/core';
function Demo() {
return (
<>
<Code>autoContrast: true</Code>
<Group mt="xs" mb="lg">
<Button color="lime.4" autoContrast>
Lime.4 button
</Button>
<Button color="blue.2" autoContrast>
Blue.2 button
</Button>
<Button color="orange.3" autoContrast>
Orange.3 button
</Button>
</Group>
<Code>autoContrast: false</Code>
<Group mt="xs">
<Button color="lime.4">Lime.4 button</Button>
<Button color="blue.2">Blue.2 button</Button>
<Button color="orange.3">Orange.3 button</Button>
</Group>
</>
);
}
autoContrast
checks whether the given color luminosity is above or below the luminanceThreshold
value
and changes text color to either theme.white
or theme.black
accordingly:
import { Button, createTheme, MantineProvider, Stack } from '@mantine/core';
const theme = createTheme({
autoContrast: true,
luminanceThreshold: 0.3,
});
function Wrapper(props: any) {
const buttons = Array(10)
.fill(0)
.map((_, index) => (
<Button key={index} color={`blue.${index}`}>
Button
</Button>
));
return (
<MantineProvider theme={theme}>
<Stack>{buttons}</Stack>
</MantineProvider>
);
}
Color functions improvements
alpha
, lighten
and darken
functions now support CSS variables (with color-mix) and OKLCH colors.
All functions are available both in @mantine/core
(.ts
/.js
files) and postcss-preset-mantine (.css
files, requires version 1.12.0 or higher).
In .css
files:
.demo-alpha {
color: alpha(var(--mantine-color-red-4), 0.5);
border: 1px solid alpha(#ffc, 0.2);
}
.demo-lighten-darken {
color: lighten(var(--mantine-color-red-4), 0.5);
border: 1px solid darken(#ffc, 0.2);
}
Will be transformed to:
.demo-alpha {
color: color-mix(in srgb, var(--mantine-color-red-4), transparent 50%);
border: 1px solid color-mix(in srgb, #ffc, transparent 80%);
}
.demo-lighten-darken {
color: color-mix(in srgb, var(--mantine-color-red-4), white 50%);
border: 1px solid color-mix(in srgb, #ffc, black 20%);
}
In .ts
/.js
files:
import { alpha, lighten } from '@mantine/core';
alpha('#4578FC', 0.45); // -> rgba(69, 120, 252, 0.45)
alpha('var(--mantine-color-gray-4)', 0.74);
// -> color-mix(in srgb, var(--mantine-color-gray-4), transparent 26%)
lighten('#4578FC', 0.45); // -> #a3c1ff
lighten('var(--mantine-color-gray-4)', 0.74);
// -> color-mix(in srgb, var(--mantine-color-gray-4), white 74%)
Note that alpha
function is a replacement for rgba
. It was renamed to
have a more clear meaning, as it can now be used with CSS variables and OKLCH colors.
rgba
function is still available as an alias for alpha
function.
enhanceGetInputProps
@mantine/form
now supports enhanceGetInputProps. enhanceGetInputProps
is a function that can be used to add additional props to the object returned by form.getInputProps
.
You can define it in useForm
hook options. Its argument is an object with the following properties:
inputProps
– object returned byform.getInputProps
by defaultfield
– field path, first argument ofform.getInputProps
, for examplename
,user.email
,users.0.name
options
– second argument ofform.getInputProps
, for example{ type: 'checkbox' }
, can be used to pass additional
options toenhanceGetInputProps
functionform
– form instance
Example of using enhanceGetInputProps
to disable input based on field path:
import { NumberInput, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';
interface FormValues {
name: string;
age: number | string;
}
function Demo() {
const form = useForm<FormValues>({
initialValues: { name: '', age: '' },
enhanceGetInputProps: (payload) => ({
disabled: payload.field === 'name',
}),
});
return (
<>
<TextInput {...form.getInputProps('name')} label="Name" placeholder="Name" />
<NumberInput {...form.getInputProps('age')} label="Age" placeholder="Age" mt="md" />
</>
);
}
Example of using enhanceGetInputProps
to add additional props to the input based on option passed to form.getInputProps
:
import { NumberInput, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';
interface FormValues {
name: string;
age: number | string;
}
function Demo() {
const form = useForm<FormValues>({
initialValues: { name: '', age: '' },
enhanceGetInputProps: (payload) => {
if (payload.options.fieldType === 'name') {
return {
label: 'Your name',
placeholder: 'Your name',
withAsterisk: true,
description: 'Your personal information is stored securely. (Just kidding!)',
};
}
return {};
},
});
return (
<>
<TextInput {...form.getInputProps('name', { fieldType: 'name' })} />
<NumberInput {...form.getInputProps('age')} label="Age" placeholder="Age" mt="md" />
</>
);
}
form.initialize
@mantine/form
now supports form.initialize
handler.
When called form.initialize
handler sets initialValues
and values
to the same value
and marks form as initialized. It can be used only once, next form.initialize
calls
are ignored.
form.initialize
is useful when you want to sync form values with backend API response:
import { Button, NumberInput, TextInput } from '@mantine/core';
import { isInRange, isNotEmpty, useForm } from '@mantine/form';
interface FormValues {
name: string;
age: number | string;
}
function apiRequest(): Promise<FormValues> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ name: 'John Doe', age: 25 });
}, 1000);
});
}
function Demo() {
const form = useForm<FormValues>({
initialValues: { name: '', age: 0 },
validate: {
name: isNotEmpty('Name is required'),
age: isInRange({ min: 18 }, 'You must be at least 18 to register'),
},
});
return (
<>
<TextInput {...form.getInputProps('name')} label="Name" placeholder="Name" />
<NumberInput {...form.getInputProps('age')} label="Age" placeholder="Age" mt="md" />
<Button onClick={() => apiRequest().then((values) => form.initialize(values))} mt="md">
Initialize form
</Button>
</>
);
}
Example with TanStack Query (react-query):
import { useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useForm } from '@mantine/form';
function Demo() {
const query = useQuery({
queryKey: ['current-user'],
queryFn: () => fetch('/api/users/me').then((res) => res.json()),
});
const form = useForm({
initialValues: {
name: '',
email: '',
},
});
useEffect(() => {
if (query.data) {
// Even if query.data changes, form will be initialized only once
form.initialize(query.data);
}
}, [query.data]);
}
Note that form.initialize
will erase all values that were set before it was called.
It is usually a good idea to set readOnly
or disabled
on all form fields before
form.initialize
is called to prevent data loss. You can implement this with
enhanceGetInputProps:
import { NumberInput, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';
interface FormValues {
name: string;
age: number | string;
}
function Demo() {
const form = useForm<FormValues>({
initialValues: { name: '', age: '' },
enhanceGetInputProps: (payload) => {
if (!payload.form.initialized) {
return { disabled: true };
}
return {};
},
});
return (
<>
<TextInput {...form.getInputProps('name')} label="Your name" placeholder="Your name" />
<NumberInput {...form.getInputProps('age')} label="Age" placeholder="Age" mt="md" />
<Button onClick={() => form.initialize({ name: 'John', age: 20 })} mt="md">
Initialize form
</Button>
</>
);
}
valibot form resolver
@mantine/form
now supports validbot schema resolver:
yarn add valibot mantine-form-valibot-resolver
Basic fields validation:
import { valibotResolver } from 'mantine-form-valibot-resolver';
import { email, minLength, minValue, number, object, string } from 'valibot';
import { useForm } from '@mantine/form';
const schema = object({
name: string([minLength(2, 'Name should have at least 2 letters')]),
email: string([email('Invalid email')]),
age: number([minValue(18, 'You must be at least 18 to create an account')]),
});
const form = useForm({
initialValues: {
name: '',
email: '',
age: 16,
},
validate: valibotResolver(schema),
});
form.validate();
form.errors;
// -> {
// name: 'Name should have at least 2 letters',
// email: 'Invalid email',
// age: 'You must be at least 18 to create an account'
// }
Nested fields validation
import { valibotResolver } from 'mantine-form-valibot-resolver';
import { minLength, object, string } from 'valibot';
import { useForm } from '@mantine/form';
const nestedSchema = object({
nested: object({
field: string([minLength(2, 'Field should have at least 2 letters')]),
}),
});
const form = useForm({
initialValues: {
nested: {
field: '',
},
},
validate: valibotResolver(nestedSchema),
});
form.validate();
form.errors;
// -> {
// 'nested.field': 'Field should have at least 2 letters',
// }
List fields validation:
import { valibotResolver } from 'mantine-form-valibot-resolver';
import { array, minLength, object, string } from 'valibot';
import { useForm } from '@mantine/form';
const listSchema = object({
list: array(
object({
name: string([minLength(2, 'Name should have at least 2 letters')]),
})
),
});
const form = useForm({
initialValues: {
list: [{ name: '' }],
},
validate: valibotResolver(listSchema),
});
form.validate();
form.errors;
// -> {
// 'list.0.name': 'Name should have at least 2 letters',
// }
ScrollArea scrollbars prop
ScrollArea now supports scrollbars
prop, which allows controlling directions at which scrollbars should be rendered.
Supported values are x
, y
and xy
. If scrollbars="y"
is set, only the vertical scrollbar will be rendered, and it will not be possible to scroll horizontally:
import { Box, ScrollArea } from '@mantine/core';
function Demo() {
return (
<ScrollArea w={300} h={200} scrollbars="y">
<Box w={600}>{/* ... content */}</Box>
</ScrollArea>
);
}
Title lineClamp prop
Title component now supports lineClamp
prop, which allows truncating text after a specified number of lines:
import { Box, Title } from '@mantine/core';
function Demo() {
return (
<Box maw={400}>
<Title order={2} lineClamp={2}>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure doloremque quas dolorum. Quo
amet earum alias consequuntur quam accusamus a quae beatae, odio, quod provident consectetur
non repudiandae enim adipisci?
</Title>
</Box>
);
}
Primary color CSS variables
CSS variables for primary color are now available, you can use the following variables in your styles:
--mantine-primary-color-0
--mantine-primary-color-1
--mantine-primary-color-2
--mantine-primary-color-3
--mantine-primary-color-4
--mantine-primary-color-5
--mantine-primary-color-6
--mantine-primary-color-7
--mantine-primary-color-8
--mantine-primary-color-9
--mantine-primary-color-contrast
--mantine-primary-color-filled
--mantine-primary-color-filled-hover
--mantine-primary-color-light
--mantine-primary-color-light-hover
--mantine-primary-color-light-color
Help center
Help center is a new website with guides, tutorials and frequently
asked questions. Currently, it has 14 questions, more FAQs will be added in the next releases.
- Is there DataGrid component that I can use with Mantine?
- MantineProvider was not found in component tree. What should I do?
- Can I use Mantine components as server components?
- Can I use Mantine with Create React App (CRA)?
- How can I lint CSS files?
- How to update Mantine dependencies?
- How can I add hover styles to an element?
- How can I get current color scheme value in JavaScript?
- Can I use private CSS variables to style components?
- How can I disable all inputs/inputs group inside form?
- How to use Dropzone with @mantine/form?
- How to call a function when Modal/Drawer closes and animation completes?
- How to prevent Modal from closing?
- What is the difference between searchable Select and Autocomplete?
Documentation updates
- form.getInputProps guide now has a separate page. It describes
form.getInputProps
,enhanceGetInputProps
and how to integrateform.getInputProps
with custom inputs. - assignRef function documentation has been added.
- clampUseMovePosition function documentation has been added.
- Additional documentation about hook arguments and types has been added to use-hotkeys.
- UseListStateHandlers type documentation has been added.
- Functions reference page has been added. Currently, it contains all functions that are exported from
@mantine/hooks
package. It is planned to document functions from other packages in next releases. - Examples on how to change the close icon have been added to Drawer and Modal components.
variantColorsResolver
demos have been added to ActionIcon, ThemeIcon and Badge components.
Other changes
- RichTextEditor no longer depends on
@tabler/icons
package. It is no longer required to install@tabler/icons
package to useRichTextEditor
component. Icons used in the editor are now a part of the@mantine/tiptap
package. This change improves bundling performance in several cases (mostly when usingRichTextEditor
in Next.js apps). - Badge component now supports
circle
prop which makes the badge round. - You can now reference theme values in
ff
style prop withmono
,text
andheading
values:<Box ff="mono" />
. - RichTextEditor now has
RichTextEditor.Undo
andRichTextEditor.Redo
controls. - A new
luminance
color function was added. It returns color luminance as a number between 0 and 1. - All components now support new
flex
style prop which allows settingflex
CSS property on the root element. - Collapse markup was reduced to single element, it can now be used in contexts that were previously not supported, for example, table rows.
stepHoldDelay
andstepHoldInterval
props have been added to NumberInput.- mantine-form-zod-resolver now supports
errorPriority
configuration which allows controlling the order of errors specified in the schema. This feature requires updatingmantine-form-zod-resolver
to version 1.1.0 or higher. - CloseButton now supports
icon
prop, which allows overriding default icon. It is useful when it is not possible to replaceCloseButton
, for example, in Drawer component. - Select component now calls
onChange
with an additional argument – option object. It containslabel
,value
and optionaldisabled
properties. - It is now possible to define CSS variables in
styles
prop of all components. - New use-in-viewport hook
- All Vite templates have been updated to Vite 5.0 and Vitest 1.0