View changelog with demos on mantine.dev website
AngleSlider component
New AngleSlider component:
import { AngleSlider, Group } from '@mantine/core';
function Demo() {
return (
<Group p="lg" gap={50}>
<AngleSlider
aria-label="Angle slider"
formatLabel={(value) => `${value}°`}
size={100}
restrictToMarks
marks={[
{ value: 0 },
{ value: 45 },
{ value: 90 },
{ value: 135 },
{ value: 180 },
{ value: 225 },
{ value: 270 },
{ value: 315 },
]}
/>
<AngleSlider
aria-label="Angle slider"
formatLabel={(value) => `${value}°`}
size={100}
marks={[
{ value: 0, label: '0°' },
{ value: 45, label: '45°' },
{ value: 90, label: '90°' },
{ value: 135, label: '135°' },
{ value: 180, label: '180°' },
{ value: 225, label: '225°' },
{ value: 270, label: '270°' },
{ value: 315, label: '315°' },
]}
/>
</Group>
);
}
RadialBarChart component
New RadialBarChart component:
import { RadialBarChart } from '@mantine/charts';
const data = [
{ name: '18-24', value: 31.47, color: 'blue.7' },
{ name: '25-29', value: 26.69, color: 'orange.6' },
{ name: '30-34', value: 15.69, color: 'yellow.7' },
{ name: '35-39', value: 8.22, color: 'cyan.6' },
{ name: '40-49', value: 8.63, color: 'green' },
{ name: '50+', value: 2.63, color: 'pink' },
{ name: 'unknown', value: 6.67, color: 'gray' },
];
function Demo() {
return <RadialBarChart data={data} dataKey="value" h={280} withLabels />;
}
FunnelChart component
New FunnelChart component:
import { FunnelChart } from '@mantine/charts';
const data = [
{ name: 'USA', value: 400, color: 'indigo.6' },
{ name: 'India', value: 300, color: 'yellow.6' },
{ name: 'Japan', value: 100, color: 'teal.6' },
{ name: 'Other', value: 200, color: 'gray.6' },
];
function Demo() {
return <FunnelChart data={data} />;
}
Modal.Stack and Drawer.Stack components
New Modal.Stack and Drawer.Stack components simplify usage of multiple modals/drawers at the same time.
Use Modal.Stack
component to render multiple modals at the same time.
Modal.Stack
keeps track of opened modals, manages z-index values, focus trapping
and closeOnEscape
behavior. Modal.Stack
is designed to be used with useModalsStack
hook.
Differences from using multiple Modal
components:
Modal.Stack
manages z-index values – modals that are opened later will always have higher z-index value disregarding their order in the DOMModal.Stack
disables focus trap andEscape
key handling for all modals except the one that is currently opened- Modals that are not currently opened are present in the DOM but are hidden with
opacity: 0
andpointer-events: none
- Only one overlay is rendered at a time
import { Button, Group, Modal, useModalsStack } from '@mantine/core';
function Demo() {
const stack = useModalsStack(['delete-page', 'confirm-action', 'really-confirm-action']);
return (
<>
<Modal.Stack>
<Modal {...stack.register('delete-page')} title="Delete this page?">
Are you sure you want to delete this page? This action cannot be undone.
<Group mt="lg" justify="flex-end">
<Button onClick={stack.closeAll} variant="default">
Cancel
</Button>
<Button onClick={() => stack.open('confirm-action')} color="red">
Delete
</Button>
</Group>
</Modal>
<Modal {...stack.register('confirm-action')} title="Confirm action">
Are you sure you want to perform this action? This action cannot be undone. If you are
sure, press confirm button below.
<Group mt="lg" justify="flex-end">
<Button onClick={stack.closeAll} variant="default">
Cancel
</Button>
<Button onClick={() => stack.open('really-confirm-action')} color="red">
Confirm
</Button>
</Group>
</Modal>
<Modal {...stack.register('really-confirm-action')} title="Really confirm action">
Jokes aside. You have confirmed this action. This is your last chance to cancel it. After
you press confirm button below, action will be performed and cannot be undone. For real
this time. Are you sure you want to proceed?
<Group mt="lg" justify="flex-end">
<Button onClick={stack.closeAll} variant="default">
Cancel
</Button>
<Button onClick={stack.closeAll} color="red">
Confirm
</Button>
</Group>
</Modal>
</Modal.Stack>
<Button onClick={() => stack.open('delete-page')}>Open modal</Button>
</>
);
}
useModalsStack/useDrawersStack hooks
useModalsStack
hook provides an easy way to control multiple modals at the same time.
It accepts an array of unique modals ids and returns an object with the following properties:
interface ModalStackReturnType<T extends string> {
// Current opened state of each modal
state: Record<T, boolean>;
// Opens modal with the given id
open: (id: T) => void;
// Closes modal with the given id
close: (id: T) => void;
// Toggles modal with the given id
toggle: (id: T) => void;
// Closes all modals within the stack
closeAll: () => void;
// Returns props for modal with the given id
register: (id: T) => {
opened: boolean;
onClose: () => void;
stackId: T;
};
}
Example of using useModalsStack
with Modal
component:
import { Modal, useModalsStack } from '@mantine/core';
function Demo() {
const stack = useModalsStack(['first', 'second']);
return (
<>
<Modal {...stack.register('first')}>First</Modal>
<Modal {...stack.register('second')}>Second</Modal>
<Button onClick={() => stack.open('first')}>Open first</Button>
</>
);
}
Restrict Slider selection to marks
Slider component now supports restrictToMarks
prop that restricts slider value to marks only.
Note that in this case step
prop is ignored:
import { Slider } from '@mantine/core';
function Demo() {
return (
<Slider
restrictToMarks
defaultValue={25}
marks={Array.from({ length: 5 }).map((_, index) => ({ value: index * 25 }))}
/>
);
}
BarChart SVG pattern fill
BarChart now can be used with SVG pattern fill:
import { BarChart } from '@mantine/charts';
import { data } from './data';
function Demo() {
return (
<BarChart
h={300}
data={mixedStackData}
dataKey="month"
series={[
{ name: 'Smartphones', color: 'url(#crosshatch)', stackId: 'a' },
{ name: 'Laptops', color: 'blue.6', stackId: 'b' },
{ name: 'Tablets', color: 'url(#diagonalStripes)', stackId: 'b' },
]}
>
<defs>
<pattern
id="diagonalStripes"
patternUnits="userSpaceOnUse"
width={6}
height={8}
patternTransform="rotate(45)"
>
<rect
width="2"
height="8"
transform="translate(0,0)"
fill="color-mix(in lch, var(--mantine-color-teal-6) 70%, rgba(0,0,0,0))"
/>
</pattern>
<pattern id="crosshatch" patternUnits="userSpaceOnUse" width={8} height={8}>
<path
d="M 0 0 L 8 0 L 8 8 L 0 8 Z"
fill="none"
stroke="color-mix(in lch, var(--mantine-color-indigo-6) 70%, rgba(0,0,0,0))"
strokeWidth="1"
/>
<path
d="M 0 0 L 8 8"
stroke="color-mix(in lch, var(--mantine-color-indigo-6) 70%, rgba(0,0,0,0))"
strokeWidth="1"
/>
<path
d="M 8 0 L 0 8"
stroke="color-mix(in lch, var(--mantine-color-indigo-6) 70%, rgba(0,0,0,0))"
strokeWidth="1"
/>
</pattern>
</defs>
</BarChart>
);
}
Help center updates
- New Can I use nested inline styles with Mantine components? question
- New Can I use PostCSS function in inline styles? question
- New Why my Carousel slides are in vertical orientation? question
- New My buttons are transparent and the background is visible only on hover, what is wrong? question
- New Can I have different primary color for light and dark color schemes? question
- New How can I change body background color? question
- New My Popover dropdown closes when I click on the dropdown of nested Popover question
Other changes
- useTree hook now accepts
onNodeExpand
andonNodeCollapse
callbacks - useTree hook now returns additional
checkAllNodes
,uncheckAllNodes
andsetCheckedState
handlers - Tree component now includes
getTreeExpandedState
to generate expanded state based on the tree data - use-form now supports
form.replaceListItem
handler to replace list item at given index