Repository navigation
Releases: mantinedev/mantine
Release list
9.7.3
[@mantine/schedule]Add slotLabelInterval prop to DayView and WeekView to display time labels more often than once per hour[@mantine/schedule]Add option to customize business hours minutes and change colors[@mantine/schedule]MobileMonthView: AddwithWeekendDaysprop[@mantine/charts]Fix right Y axis children rendering (#9295)[@mantine/hooks]use-scroller: Fix next click being ignored after a drag ends by leaving the container (#9294)[@mantine/hooks]use-event-listener: Fix listener being removed after re-render when options object is passed inline (#9292)[@mantine/core]ScrollArea: Add --scrollarea-offset-size CSS variable (#9290)[@mantine/core]Cascader: Fix ArrowLeft and ArrowRight not being mirrored in RTL (#9286)[@mantine/hooks]use-throttled-callback: Handle reentrant calls (#9284)[@mantine/core]Radio, Chip: Fix readOnly prop not preventing value changes (#9282)[@mantine/core]Select: Fix onChange option argument type not including null (#9281)[@mantine/core]Switch: FixreadOnlyprop not preventing toggle (#9280)[@mantine/core]Fix searchable inputs ignoring typing when rendered in another window or iframe (#9278)[@mantine/hooks]use-focus-trap: Fix focus not being fully trapped when used with macOS Full Keyboard Access off
9.7.2
[@mantine/core]PinInput: Fix readOnly not preventing value changes on Delete, Backspace and paste (#9258)[@mantine/core]Divider: Addaria-orientation(#9259)[@mantine/core]Tooltip: Fix disabled tooltip settingaria-describedbyon its target (#9261)[@mantine/core]Transition: Fix frames and callbacks running after unmount during the first frame (#9263)[@mantine/hooks]use-scroll-into-view: Reset start time on cancel (#9265)[@mantine/core]Fix Backspace removing the last value when readOnly is set in MultiSelect and TreeSelect components (#9267)[@mantine/schedule]ResourcesDayView: Fix sticky resource labels covering the time labels row (#9268)[@mantine/hooks]use-debounced-callback: Avoid repeating completed leading calls (#9269)[@mantine/schedule]MobileMonthView: Fix multi-day event time display on start, middle and end days (#9272)[@mantine/form]AddUseContextFormtype export (#9275)[@mantine/form]Fix potential global prototype position[@mantine/tiptap]Add option to handle images pasted with other rich text elements in the image extension (#9270)
9.7.1
[@mantine/schedule]Fix startScrollTime scroll position (#9255)[@mantine/core]RollingNumber: Fix sub-pixel digit misalignment at fractional zoom levels (#9251)[@mantine/core]Tree: Add aria-expanded to tree items with children (#9247)[@mantine/core]SegmentedControl: Do not call Math.random during render (#9245)[@mantine/core]Popover: Add capture prop to control events capturing phase (#9243)[@mantine/form]Fix clearing state of unrelated fields (#9242)[@mantine/core]AngleSlider: Set aria-disabled on thumb when disabled (#9238)[@mantine/core]Combobox: Set aria-disabled on disabled Combobox.Option (#9236)[@mantine/form]Fix reorderListItem moving errors of items whose index shares a prefix with the reordered index (#9235)[@mantine/schedule]MonthView: Fix quadratic row assignment for weeks with many events (#9232)[@mantine/hooks]use-pagination: Fix single page being replaced with dots on the right side (#9229)[@mantine/core]ScrollArea: Fix wheel listener on document blocking compositor scrolling for the whole page (#9225)[@mantine/dates]DateTimePicker: Fix time not being limited by minDate and maxDate (#9221)[@mantine/core]Select, MultiSelect, Autocomplete, TagsInput: Fix listbox aria-labelledby referencing a missing label element (#9219) (#9220)[@mantine/hooks]use-debounced-state: Fix leading edge firing only once (#9214)
9.7.0 😳
View changelog with demos on mantine.dev website
Support Mantine development
You can now sponsor Mantine development with OpenCollective.
All funds are used to improve Mantine and create new features and components.
@mantine/mcp-server documentation coverage
@mantine/mcp-server now exposes 406 documentation
pages instead of 164. Previously only components were indexed – hooks, @mantine/form,
styling, theming, guides and help.mantine.dev FAQ pages are now included as
well. Changelog pages are deliberately excluded to keep search results focused on current APIs.
Documentation is now retrieved by section rather than by whole page. get_item_doc returns a page
outline (description, import statement and the list of section headings) by default, a single section
with the section argument, or the entire page with full: true. Requesting useForm this way returns
about 1KB instead of 9KB, and the largest pages drop from roughly 89KB to 4KB.
Other improvements:
- New
get_apitool – resolves a symbol such asuseFormoruseDisclosureto its TypeScript
signature and exported types without knowing which page documents it - Ranked search –
search_docsresults point at the specific section that matched, so a query like
"validate a form with zod" resolves to thezodsection of the schema validation page - Search synonyms – queries now match the search keywords maintained in the documentation, so
"command palette" finds Spotlight - More filters –
list_itemsacceptsgroup,categoryandpackagein addition tokind - Hook signatures –
get_item_propsreturns the TypeScript signature for hooks, and points at the
relevant section for pages that document their API in prose
The server was also migrated to the official Model Context Protocol SDK, so the protocol version is
negotiated with the client instead of being pinned.
For setup details, supported tools, and client-specific instructions, see Mantine with LLMs.
Tour component
New Tour component provides interactive step-by-step application onboarding.
It highlights target elements with a spotlight overlay and displays tooltips with navigation controls.
Supports both guided (sequential) and beacon (non-sequential) modes.
Toolbar component
New Toolbar component provides an accessible toolbar container with roving tabindex
keyboard navigation, toggle groups with single/multiple selection, visual grouping, and dividers.
Styling is similar to RichTextEditor toolbar.
Toggle component
New Toggle component is a button that can be toggled between active and inactive states:
JsonViewer component
New JsonViewer component can be used to display complex JSON
structures with expand/collapse, type indicators, copy to clipboard, and other features:
Light Checkbox and Radio variant
Checkbox and Radio components now support variant="light" –
the indicator uses a light background color with a colored icon, similar to the light variant
available in other components like Button:
import { Radio, Checkbox, Stack } from '@mantine/core';
function Demo() {
return (
<Stack gap={7}>
<Checkbox variant="light" label="Light Checkbox" defaultChecked />
<Checkbox variant="light" label="Light indeterminate Checkbox" indeterminate />
<Radio variant="light" label="Light Radio" defaultChecked />
</Stack>
);
}RichTextEditor image upload
RichTextEditor now supports image upload with loading states.
Images can be uploaded via toolbar button, drag and drop, or paste.
During upload, a local preview is shown with a loading indicator.
Configuring getUploadImageExtension is enough to enable uploads – onImageUpload and
onImageUploadError props of RichTextEditor are optional overrides for the toolbar control.
onImageUpload can resolve either to a string or to { src, alt, title } (new exported
ImageUploadResult type) to set alternative text on the uploaded image. Several files picked,
dropped or pasted together are inserted in the order they were selected and are undone as one step.
import TipTapImage from '@tiptap/extension-image';
import { useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { getUploadImageExtension, ImageUploadResult, RichTextEditor } from '@mantine/tiptap';
function handleImageUpload(file: File): Promise<ImageUploadResult> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ src: URL.createObjectURL(file), alt: file.name });
}, 3000);
});
}
function Demo() {
const editor = useEditor({
shouldRerenderOnTransaction: true,
extensions: [
StarterKit,
getUploadImageExtension(TipTapImage, { onImageUpload: handleImageUpload }),
],
content: '<p>Click the image button in the toolbar, or drag & drop / paste an image into the editor.</p>',
});
return (
<RichTextEditor editor={editor}>
<RichTextEditor.Toolbar>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Bold />
<RichTextEditor.Italic />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.ImageUpload />
</RichTextEditor.ControlsGroup>
</RichTextEditor.Toolbar>
<RichTextEditor.Content />
</RichTextEditor>
);
}Schedule event overlap mode
DayView and WeekView now support eventOverlapMode prop
that controls how events overlapping in time share the horizontal space. The default columns mode
splits the available width evenly between them, which becomes unreadable once a large number of events
overlap. The new cascade mode indents each event and stacks it over the previous one, so every event
keeps a readable width no matter how many of them overlap.
The indent shrinks automatically as the group grows, so the event on top always keeps at least 60% of
the available width. Covered events can still be read and used: rest the pointer on one and it is
raised above the events covering it, which also makes its resize handles reachable. Keyboard users get
the same result by focusing the event with Tab. eventOverlapRaiseDelay prop controls how long the
pointer must rest on an event before it is raised, in milliseconds (600 by default).
import { useState } from 'react';
import { SegmentedControl, Stack } from '@mantine/core';
import { ScheduleEventOverlapMode, WeekView } from '@mantine/schedule';
import { events } from './data';
function Demo() {
const [mode, setMode] = useState<ScheduleEventOverlapMode>('cascade');
return (
<Stack>
<SegmentedControl
value={mode}
onChange={(value) => setMode(value as ScheduleEventOverlapMode)}
data={[
{ value: 'columns', label: 'columns' },
{ value: 'cascade', label: 'cascade' },
]}
/>
<WeekView
date={new Date()}
events={events}
startTime="08:00:00"
endTime="14:00:00"
eventOverlapMode={mode}
/>
</Stack>
);
}Schedule drop validation
All Schedule views can now reject a drag or resize before it is committed,
based on where the event is being dropped rather than on which event is being dragged. Previously
canDragEvent and canResizeEvent only decided whether an event was draggable or resizable at all,
so the only way to prevent a double booking was to accept the drop, notice the conflict in the
handler and not update state – which produced a snap-back with no explanation:
preventEventOverlaprejects placements that would make the event overlap another event. Pass a
function to decide per pair of events: returntrueto forbid that particular overlap.canDropEventandcanResizeEventToare called before a drop or resize is committed – return
falseto reject it.canDropExternalEventdoes the same for items dragged in from outside the schedule.onEventPlacementRejectedreports the rejection with the conflicting events and the reason.
The checks compose: a placement is allowed only when the overlap check passes and the matching
callback returns a value other than false. The overlap check runs first, so onEventPlacementRejected
can report conflicts without your code repeating the work. While the pointer is over an invalid
target the drag ghost and the resizing event get data-invalid, so the rejection is visible before the
pointer is released.
import { useState } from 'react';
import dayjs from 'dayjs';
import { Stack, Text } from '@mantine/core';
import { WeekView, ScheduleEventData } from '@mantine/schedule';
const startOfWeek = dayjs()
.subtract((dayjs().day() + 6) % 7, 'day')
.format('YYYY-MM-DD');
const initialEvents: ScheduleEventData[] = [
{
id: 1,
title: 'Standup',
start: `${startOfWeek} 09:00:00`,
end: `${startOfWeek} 09:30:00`,
color: 'blue',
},
{
id: 2,
title: 'Design review',
start: `${startOfWeek} 11:00:00`,
end: `${startOfWeek} 12:00:00`,
color: 'grape',
},
{
id:...9.6.3
[@mantine/hooks]use-click-outside: Add capture phase support (#9213)[@mantine/core]Select: Fix dropdown not closing on blur when searchable is not set (#9215)[@mantine/core]PasswordInput: Fix aria-describedby not being taken from InputWrapperContext (#9216)[@mantine/core]Fix aria-labelledby referencing a missing label element in Checkbox.Group, Radio.Group, Switch.Group (#9217)[@mantine/core]Slider: Fix thumbProps not being passed to the thumb element (#9218)[@mantine/core]Table: Fix memoized rows rerendering when Table rerenders with the same props (#6422)[@mantine/hooks]use-intersection: Use the last entry from a batched observer callback (#9019)[@mantine/hooks]use-media-query: Catch matchMedia errors when reading the initial value synchronously (#9020)[@mantine/core]Portal: Cache shared portal node lookup (#9101)[@mantine/schedule]MobileMonthView: Fix multi-day events not showing when they start in the previous month (#9153)[@mantine/form]Fix removeListItem not clearing non-nested item errors (#9180)[@mantine/core]Rating: Fix value being changed by scroll gestures on touch devices (#9159)[@mantine/notifications]Fix uneven spacing in expanded stacks (#9176)[@mantine/charts]FixtextColorandgridColorprops being passed as attributes to the DOM node (#9181)[@mantine/hooks]use-hotkeys: Fix preventDefault not being applied when other hotkey options are set (#9164)[@mantine/hooks]use-throttled-callback: Fix callback becoming unresponsive after clearTimeout (#9146)[@mantine/hooks]use-roving-index: Fix disabled items not being skipped by ArrowLeft/ArrowRight in grid mode (#9169)[@mantine/hooks]use-mask: Fix transform not being applied to the initial input value (#9170)
9.6.2
[@mantine/core]Combobox: Fix incorrectaria-selectedsetting on up/down arrows press (#9205)[@mantine/core]NumberInput: Fixminandmaxboundaries not being respected whentrimLeadingZeroesOnBluris false (#9192)[@mantine/hooks]use-mask: Fix incorrect handling of input with mixed static values (#9196)[@mantine/schedule]Add option to resize bacground events (#9190)[@mantine/schedule]MobileMonthView: Fix missing localization for all day events label (#9191)[@mantine/hooks]use-scroll-spy: Fix stale nodes being used when element cannot be resolved by the given selector[@mantine/core]ComboboxPopover: Fix incorrect focus management[@mantine/charts]GaugeChart: Fix incorrectroundCapshandling with multiple sections (#9189)[@mantine/core]NumberInput: Fix incorrect thousands separator handling on paste (#9102)
9.6.1
[@mantine/ligtbox]Add option to render custom thumbnails for video[@mantine/core]OverflowList: Fix ResizeObserver console warning (#9177)[@mantine/core]Fix incorrect escape handling in Modal and Drawer stacks (#9188)[@mantine/core]SegmentedControl: Fix indicator disappearing when data list is replaced with a list with the same length (#9175)[@mantine/lightbox]Fix circular esm dependency (#9166)[@mantine/core]Accordion: Fix incorrect border radius being applied to the contained items[@mantine/schedule]Add event overlap mode support to WeekView and DayView[@mantine/core]Menu: Fix incorrectwithinPortalprop being available[@mantine/core]Popover: Fix position not being updated when prop changes when the dropdown is opened (#9156)[@mantine/schedule]Fix same-day events ending at exclusive midnight being dropped in WeekView and DayView components (#9157)[@mantine/hooks]use-interval: Fix timer restarting when fn changes (#9158)[@mantine/core]Textarea: Fix ResizeObserver loop error when autosize textarea width changes (#9162)[@mantine/hooks]use-collapse: Fix incorrect transition state switching when used with Activity (#9160)
9.6.0 🔥
View changelog with demos on mantine.dev website
Support Mantine development
You can now sponsor Mantine development with OpenCollective.
All funds are used to improve Mantine and create new features and components.
@mantine/lightbox package
New @mantine/lightbox package – a full-screen media lightbox with carousel navigation,
zoom, thumbnails, toolbar customization, and store-based API. Supports image, video, and custom slides:
import '@mantine/lightbox/styles.css';
import { useState } from 'react';
import { Image, SimpleGrid } from '@mantine/core';
import { Lightbox, LightboxSlideData } from '@mantine/lightbox';
const images = [
'https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-1.png',
'https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-2.png',
'https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-3.png',
'https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-4.png',
'https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-5.png',
];
const slides: LightboxSlideData[] = images.map((src) => ({ src }));
function Demo() {
const [opened, setOpened] = useState(false);
const [index, setIndex] = useState(0);
return (
<>
<Lightbox
opened={opened}
onClose={() => setOpened(false)}
slides={slides}
currentIndex={index}
onIndexChange={setIndex}
/>
<SimpleGrid cols={3}>
{images.map((src, i) => (
<Image
key={src}
src={src}
radius="md"
style={{ cursor: 'pointer' }}
onClick={() => {
setIndex(i);
setOpened(true);
}}
/>
))}
</SimpleGrid>
</>
);
}Key features:
- Zoom – click to zoom on desktop, double-tap on mobile, scroll wheel and pinch gestures
- Thumbnails – bottom thumbnail strip with active indicator
- Store API – mount once, open from anywhere (same pattern as Spotlight and Notifications)
- Video slides – native video player with auto-pause on navigation
- Custom slides – render anything with custom thumbnails
- Transitions – animated open and close with configurable
transitionProps(same API as Modal) - Keyboard shortcuts – Escape, arrows, F/T/Z for fullscreen/thumbnails/zoom
- Localization – every string is defined in the
labelsprop
Notifications custom rendering
Notifications now support renderNotification prop that allows you to completely
replace the default notification with custom content. All animations (enter, exit, drag dismiss)
are preserved for custom notifications:
import { Avatar, Button, Group, rem, Text } from '@mantine/core';
import { notifications } from '@mantine/notifications';
function Demo() {
return (
<Group justify="center">
<Button
onClick={() =>
notifications.show({
autoClose: false,
renderNotification: (notification) => (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: rem(12),
padding: rem(16),
borderRadius: rem(8),
backgroundColor: 'var(--mantine-color-body)',
border: '1px solid var(--mantine-color-default-border)',
boxShadow: 'var(--mantine-shadow-lg)',
userSelect: 'none',
}}
>
<Avatar src={null} radius="xl" color="blue">
DM
</Avatar>
<div style={{ flex: 1, minWidth: 0 }}>
<Text size="sm" fw={600}>
Dan sent you a message
</Text>
<Text size="xs" c="dimmed" lineClamp={1}>
Hey, are you free for a quick call?
</Text>
<Group gap="xs" mt={8}>
<Button
size="compact-xs"
variant="filled"
onClick={() =>
notifications.hide(notification.id!)
}
>
Reply
</Button>
<Button
size="compact-xs"
variant="default"
onClick={() =>
notifications.hide(notification.id!)
}
>
Dismiss
</Button>
</Group>
</div>
</div>
),
message: '',
})
}
>
Show custom notification
</Button>
</Group>
);
}Notifications stacked layout
Notifications now support layout="stacked" prop that displays notifications in a stacked
layout where only the latest notification is fully visible, and older notifications peek out behind it:
import { Button, Group } from '@mantine/core';
import { Notifications, notifications } from '@mantine/notifications';
function Demo() {
return (
<>
{/* Replace your existing Notifications with layout="stacked" */}
<Notifications layout="stacked" />
<Group justify="center">
<Button
onClick={() => {
notifications.show({
title: 'New notification',
message: 'This notification is part of a stacked layout',
});
}}
>
Show stacked notification
</Button>
</Group>
</>
);
}ActionBar component
New ActionBar component – a fixed-position bottom bar
for bulk selection actions. Designed to be controlled by table or checkbox
selections, it provides a set of actions that can be performed on selected items.
import { useState } from 'react';
import { ActionBar, Button, Checkbox, Table, Text } from '@mantine/core';
const elements = [
{ position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
{ position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
{ position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium' },
{ position: 56, mass: 137.33, symbol: 'Ba', name: 'Barium' },
{ position: 58, mass: 140.12, symbol: 'Ce', name: 'Cerium' },
];
function Demo() {
const [selection, setSelection] = useState<number[]>([]);
const toggleRow = (position: number) =>
setSelection((current) =>
current.includes(position)
? current.filter((item) => item !== position)
: [...current, position]
);
const toggleAll = () =>
setSelection((current) =>
current.length === elements.length ? [] : elements.map((element) => element.position)
);
const rows = elements.map((element) => (
<Table.Tr
key={element.position}
bg={selection.includes(element.position) ? 'var(--mantine-color-blue-light)' : undefined}
>
<Table.Td>
<Checkbox
aria-label="Select row"
checked={selection.includes(element.position)}
onChange={() => toggleRow(element.position)}
/>
</Table.Td>
<Table.Td>{element.position}</Table.Td>
<Table.Td>{element.name}</Table.Td>
<Table.Td>{element.symbol}</Table.Td>
<Table.Td>{element.mass}</Table.Td>
</Table.Tr>
));
return (
<>
<Table>
<Table.Thead>
<Table.Tr>
<Table.Th>
<Checkbox
aria-label="Select all"
checked={selection.length === elements.length}
indeterminate={selection.length > 0 && selection.length !== elements.length}
onChange={toggleAll}
/>
</Table.Th>
<Table.Th>Element position</Table.Th>
<Table.Th>Element name</Table.Th>
<Table.Th>Symbol</Table.Th>
<Table.Th>Atomic mass</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
<ActionBar opened={selection.length > 0} onClose={() => setSelection([])} shadow="md">
<Text size="sm">{selection.length} selected</Text>
<ActionBar.Divider />
<Button variant="default" size="compact-sm">
Delete
</Button>
<Button variant="default" size="compact-sm">
Move
</Button>
<Button variant="default" size="compact-sm">
Archive
</Button>
<ActionBar.CloseButton />
</ActionBar>
</>
);
}RichTextEditor table controls
RichTextEditor now includes a set of controls for editing tables. Install and register the
Tiptap table extension (TableKit), then add
the controls to the toolbar. RichTextEditor.TableInsert opens a grid to pick the table size, and the
other controls add/remove rows and columns, toggle header row/column and merge/split cells. All table
controls are automatically disabled when the cursor is not inside a table:
import { TableKit } from '@tiptap/extension-table';
import { useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { RichTextEditor } from '@mantine/tiptap';
function Demo() {
const editor = useEditor({
extensions: [StarterKit, TableKit],
content: `
<t...9.5.2
[@mantine/hooks]use-debounced-value: Fixleading: truefiring multiple times per burst and emiting a stale value (#9119)[@mantine/schedule]Fix recurring events not working with timzones (#9112)[@mantine/dates]FixminDateused for default date in some cases (#9117)[@mantine/core]Tooltip: Fix tooltip setting NaN in top/left position style when event position values cannot be read (#9131)[@mantine/dates]TimePicker: Fix incorrect focus handling of partially filled hours field (#9128)[@mantine/core]RollingNumber: Fix incorrect copy event handling (#9132)[@mantine/core]Notification: Fix incorrectcloseButtonPropstype (#9134)[@mantine/code-highlight]Add support for lazy languages loading (#9141)[@mantine/code-highlight]CodeHighlight: Add prop to keep indentation of the first line of the code block (#9140)[@mantine/dates]Add missing formatting functions to MiniCalendarm DateInput and YarsList components[@mantine/schedule]WeekView: Improve performance of events positioning algorithm (#9075)[@mantine/form]Add new useWatchValue hook[@mantine/core]Fix Combobox-based components not working correctly with Chrome autocomplete
9.5.1
[@mantine/tiptap]Fix controls being initially disabledbefore element is focused[@mantine/tiptap]Fix source code control wrapping content with extra p tag[@mantine/hooks]use-scroll-spy: Allow usage with refs (#9025)[@mantine/core]ColorInput: Add support for fullWidth prop (#9061)[@mantine/core]Checkbox: Fix incottect indeterminate aria attributes handling in Checkbox.Card (#9095)[@mantine/core]FloatingIndicator: Fix position and size calculation under scaled ancestors (#9071)[@mantine/core]Tooltip: Add interactive prop support (#9072)[@mantine/core]Cascader: Add safe area polygon support[@mantine/core]PasswordInput: Add option to change whether the visibility toggle is focusable (#9090)[@mantine/charts]ScatterChart: Add option to add second y axis[@mantine/schedule]YearView: AddrenderDayprop support[@mantine/schedule]YearView: Add option to hide weekend days[@mantine/core]InputWrapper: Fixcomponent: divtriggering typescript error if passed todescriptionProps[@mantine/schedule]ResourcesMonthView: Add option to resize events[@mantine/core]FloatingWindow: Add support foronSizeChangeandonResizeStartprops (#9085)