apps/mantine.dev/src/pages/changelog/9-0-0.mdx
import { BarsListDemos, CalendarDemos, CardDemos, CheckboxDemos, CollapseDemos, ComboboxDemos, DatePickerInputDemos, DayViewDemos, FloatingWindowDemos, FormDemos, HighlightDemos, MarqueeDemos, MobileMonthViewDemos, MonthViewDemos, MultiSelectDemos, OverflowListDemos, PaginationDemos, ScheduleDemos, ScrollAreaDemos, ScrollerDemos, SimpleGridDemos, SliderDemos, TextInputDemos, UseCollapseDemos, UseFloatingWindowDemos, UseHorizontalCollapseDemos, UseScrollerDemos, WeekViewDemos, YearViewDemos } from '@docs/demos'; import { Layout } from '@/layout'; import { MDX_DATA } from '@/mdx';
export default Layout(MDX_DATA.Changelog900);
You can now sponsor Mantine development with OpenCollective. All funds are used to improve Mantine and create new features and components.
<SponsorButton />This changelog covers breaking changes and new features in Mantine 9.0. To migrate your application to Mantine 9.0, follow 8.x → 9.x migration guide.
Starting from Mantine 9.0, the following dependencies are required:
@mantine/* packages@mantine/tiptap (migration guide)@mantine/charts (no migration required)New @mantine/schedule package provides a complete set of
calendar scheduling components for React applications. It includes multiple view levels,
drag-and-drop event management, and extensive customization options.
Schedule is a unified container component that combines all views with built-in navigation and view switching. Drag events to reschedule them:
<Demo data={ScheduleDemos.dragDrop} demoProps={{ defaultExpanded: false }} />
DayView displays a single day with configurable time slots, all-day event section, current time indicator, and business hours highlighting. Drag events to reschedule them:
<Demo data={DayViewDemos.dragDrop} demoProps={{ defaultExpanded: false }} />
WeekView shows a weekly calendar grid with time slots, week numbers, weekend day toggling, and multi-day event spanning. Drag events across days and time slots:
<Demo data={WeekViewDemos.dragDrop} demoProps={{ defaultExpanded: false }} />
MonthView displays a monthly calendar grid with event overflow handling, outside days display, and week numbers. Drag events to different days:
<Demo data={MonthViewDemos.dragDrop} demoProps={{ defaultExpanded: false }} />
YearView provides a 12-month year overview organized by quarters with day-level event indicators:
<Demo data={YearViewDemos.usage} demoProps={{ defaultExpanded: false }} />
MobileMonthView is a mobile-optimized month view with event details panel for the selected day:
<Demo data={MobileMonthViewDemos.usage} demoProps={{ defaultExpanded: false }} />
To get started, follow the getting started guide.
Collapse component now supports horizontal orientation:
<Demo data={CollapseDemos.horizontal} />New use-collapse hook is the hook version of Collapse component.
It allows animation of height from 0 to auto and vice versa.
use-horizontal-collapse works the same way as use-collapse but animates width instead of height:
New use-floating-window hook allows creating floating draggable elements:
<Demo data={UseFloatingWindowDemos.usage} />FloatingWindow provides component API for use-floating-window hook:
<Demo data={FloatingWindowDemos.usage} />New OverflowList component displays list of items and collapses the overflowing items into a single element:
<Demo data={OverflowListDemos.usage} />New Marquee component creates continuous scrolling animation for content:
<Demo data={MarqueeDemos.usage} />New Scroller component displays horizontally scrollable content with navigation controls. It supports native scrolling via trackpad, shift + mouse wheel, touch gestures, and mouse drag:
<Demo data={ScrollerDemos.usage} />New use-scroller hook provides logic for creating custom scrollable containers with navigation controls:
<Demo data={UseScrollerDemos.usage} demoProps={{ defaultExpanded: false }} />
New BarsList component displays a list of horizontal bars with names and values. It supports custom colors, auto contrast, value formatting, and custom bar rendering:
<Demo data={BarsListDemos.usage} />Card component now supports horizontal orientation:
<Demo data={CardDemos.horizontal} demoProps={{ defaultExpanded: false }} />
Checkbox.Group and Switch.Group now support maxSelectedValues prop to limit the number of selected values.
When the limit is reached, the remaining controls are disabled and cannot be selected.
All Mantine input components based on Input component now support loading prop.
Set loading prop to display a loading indicator. By default, the loader is displayed on the right side of the input.
You can change the position with the loadingPosition prop to 'left' or 'right'. This is useful for async operations like API calls, searches, or validations:
MultiSelect and TagsInput components now support renderPill prop to customize pill rendering:
All clearable input components now support clearSectionMode prop that determines how the clear button and rightSection are rendered:
'both' (default) – render both the clear button and rightSection'rightSection' – render only the user-supplied rightSection, ignore clear button'clear' – render only the clear button, ignore rightSectionThis prop is supported by Select, Autocomplete, MultiSelect, TagsInput, FileInput, DateInput, DatePickerInput, MonthPickerInput, YearPickerInput, TimePicker, and DateTimePicker.
<Demo data={DatePickerInputDemos.clearSectionMode} />use-form validation rules can now be async – return a Promise that resolves to an
error message or null. When all rules are synchronous, form.validate(), form.validateField() and
form.isValid() return their results directly (not wrapped in a Promise). When any rule is async,
these methods return promises instead. TypeScript infers the correct return type based on your
validation rules, so you get precise types without manual annotations.
The form.validating property is true while any async validation is in progress, and
form.isValidating(path) checks individual fields. The validating state is never set for
forms with only synchronous rules.
Each rule receives an AbortSignal as the fourth argument. The signal is aborted when a newer
validation supersedes the current one, which you can use to cancel in-flight HTTP requests.
When using async validation with validateInputOnChange, set validateDebounce to avoid
firing an API call on every keystroke:
use-form now supports passing second type argument TransformedValues to define the type of
transformed values returned by form.getTransformedValues and form.onSubmit:
import { useForm } from '@mantine/form';
interface FormValues {
name: string;
locationId: string;
}
interface TransformedValues {
name: string;
locationId: number;
}
function Demo() {
const form = useForm<FormValues, TransformedValues>({
mode: 'uncontrolled',
initialValues: {
name: '',
locationId: '2',
},
transformValues: (values) => ({
...values,
locationId: Number(values.locationId),
}),
});
}
SegmentedControl, Select, MultiSelect,
Chip.Group, Switch.Group, Checkbox.Group and Radio.Group
now support generic value type. You can pass primitive values (numbers, strings, booleans, bigint)
as the type argument. The generic type is used for value, defaultValue, onChange and other props.
For example, generic type can now be used with SegmentedControl to specify string union:
import { SegmentedControl } from '@mantine/core';
function Demo() {
return (
<SegmentedControl<'orange' | 'grape' | 'apple'>
data={[
{ value: 'orange', label: 'Orange' },
{ value: 'grape', label: 'Grape' },
{ value: 'apple', label: 'Apple' },
]}
/>
);
}
Combobox component now supports virtualization
with the useVirtualizedCombobox hook. The hook does not depend on any specific virtualization library.
The recommended option is @tanstack/react-virtual.
Example of implementation with useVirtualizedCombobox and @tanstack/react-virtual:
You can find more virtualization examples on the Combobox examples page.
Highlight component now supports custom colors for individual highlight terms.
You can provide an array of objects with text and color properties to assign different colors
to different highlighted terms:
Highlight component now supports wholeWord prop to match only complete words.
When enabled, 'the' will not match 'there' or 'theme':
Pagination component and use-pagination hook now support startValue prop
to define the starting page number. For example, with startValue={5} and total={15},
the pagination range will be from 5 to 15:
Grid component no longer uses negative margins for spacing between columns.
Instead, it now uses native CSS gap property, which means you no longer need to use
overflow="hidden" to prevent content overflow caused by negative margins.
Slider and RangeSlider components now support vertical orientation:
<Demo data={SliderDemos.vertical} />SimpleGrid component now supports minColWidth prop to use CSS Grid auto-fill/auto-fit
to automatically adjust the number of columns based on available space and minimum column width.
When minColWidth is set, the cols prop is ignored. Use autoFlow prop to switch between
auto-fill (default) and auto-fit behavior.
SimpleGrid also now supports autoRows prop to control the size of
implicitly created grid rows:
Calendar, DatePicker, MonthPicker and YearPicker
components now support fullWidth prop to make the calendar stretch to fill 100% of its parent container width:
Many Mantine components and hooks now provide namespace exports for related types. For example, use-disclosure hook types can now be accessed like this:
import { useDisclosure } from '@mantine/hooks';
const options: useDisclosure.Options = {
onOpen: () => console.log('open'),
onClose: () => console.log('close'),
};
function Demo() {
const [opened, handlers] = useDisclosure(options);
}
Example of using namespace types with Button props type:
import { Button } from '@mantine/core';
const buttonProps: Button.Props = {
variant: 'filled',
size: 'md',
disabled: false,
};
function Demo() {
return <Button {...buttonProps}>Click me</Button>;
}
New fontWeights property was added to the theme object.
It allows you to control font-weight values used across all components.
The default values are:
regular – 400medium – 600bold – 700Each value is mapped to a CSS variable: --mantine-font-weight-regular, --mantine-font-weight-medium, --mantine-font-weight-bold.
All components that previously used hardcoded font-weight values now use these CSS variables.
For example, to revert the medium font weight from 600 back to 500 (the default in Mantine 8):
import { createTheme, MantineProvider } from '@mantine/core';
const theme = createTheme({
fontWeights: {
medium: '500',
},
});
function Demo() {
return (
<MantineProvider theme={theme}>
</MantineProvider>
);
}
Mantine now includes @mantine/mcp-server package that exposes Mantine
documentation over Model Context Protocol.
It allows AI tools to query Mantine docs and props data through MCP tools instead of raw web scraping.
The server uses static data generated from Mantine documentation and serves:
list_itemsget_item_docget_item_propssearch_docsThis setup is useful in agent workflows where tools can call MCP functions directly to retrieve structured data and reduce prompt size.
Basic server configuration:
{
"mcpServers": {
"mantine": {
"command": "npx",
"args": ["-y", "@mantine/mcp-server"],
"env": {
"MANTINE_MCP_DATA_URL": "https://mantine.dev/mcp"
}
}
}
}
For setup details, supported tools, and client-specific instructions, see Mantine with LLMs.
Mantine skills for AI coding agents are documented in the Mantine with LLMs guide.
The guide includes:
mantinedev/skillsNew isUrl and isOneOf validators were added to @mantine/form package:
isUrl – validates that the value is a valid URL. Supports custom protocols and localhost option.isOneOf – validates that the value is included in the given list of allowed values.import { isOneOf, isUrl, useForm } from '@mantine/form';
const form = useForm({
mode: 'uncontrolled',
initialValues: { website: '', role: '' },
validate: {
website: isUrl('Invalid URL'),
role: isOneOf(['admin', 'user'], 'Invalid role'),
},
});
@mantine/form now has built-in support for Standard Schema,
a community specification implemented by Zod v4, Valibot, ArkType, and other schema libraries.
Use schemaResolver to validate forms with any compliant library without installing
a separate resolver package:
import { z } from 'zod/v4';
import { useForm, schemaResolver } from '@mantine/form';
const schema = z.object({
name: z.string().min(2, { error: 'Name should have at least 2 letters' }),
email: z.email({ error: 'Invalid email' }),
age: z.number().min(18, { error: 'You must be at least 18 to create an account' }),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: { name: '', email: '', age: 16 },
validate: schemaResolver(schema, { sync: true }),
});
Pass { sync: true } when your schema is synchronous to get synchronous return types
for form.validate(), form.validateField(), and form.isValid().
AppShell component now supports mode="static" which renders
all AppShell elements as part of the normal document flow using CSS Grid instead of
fixed positioning. Static mode supports layout="alt" to place navbar and aside
at full height with header and footer adjusted between them.
See AppShell examples for more details.
ScrollArea component now supports startScrollPosition prop to set the initial scroll
position when the component mounts:
Five hooks — usePageLeave, useWindowEvent, useHotkeys, useClickOutside, and useCollapse —
have been updated to use React 19's stable useEffectEvent. Previously these hooks captured stale
closures or caused unnecessary event listener re-registrations when non-memoized callbacks were
passed. With useEffectEvent, each hook registers a single stable listener that always calls the
latest version of the provided callback, so wrapping callbacks in useCallback or useMemo is no
longer required.
Transition, Collapse, Tabs.Panel,
Stepper, and Tree now use React 19's
Activity component when keepMounted is set.
Activity preserves the state of hidden subtrees — form inputs, scroll positions, and any other
component state survive while the content is not visible. Stepper and Tree gain a new
keepMounted prop; all other components already had it.
import { useState } from 'react';
import { Stepper, TextInput } from '@mantine/core';
function Demo() {
const [active, setActive] = useState(0);
// TextInput values are preserved when navigating between steps
return (
<Stepper active={active} onStepClick={setActive} keepMounted>
<Stepper.Step label="Step 1">
<TextInput label="Value survives navigation" />
</Stepper.Step>
<Stepper.Step label="Step 2">
<TextInput label="Value survives navigation" />
</Stepper.Step>
</Stepper>
);
}
FormData section was added to all inputs componentssuperjson librarypauseResetOnHover="notification" to keep the previous behavior of pausing only the hovered notification.{ pinned: boolean; scrollProgress: number } object instead of a plain boolean. scrollProgress is a value between 0 (fully hidden) and 1 (fully visible) that can be used for scroll-linked reveal animations. A new scrollDistance option controls how many pixels of scrolling are required to fully reveal or hide the element (default: 100).'up', 'down', or 'unknown', handles resize events to avoid false direction changes, and always uses the latest state without stale closure issues.theme.defaultRadius was changed from sm (4px) to md (8px)light variant in all components now uses different colors values without transparency to improve contrastmod prop now converts camelCase keys to kebab-case for data attributes in all components@mantine/form package now includes built-in Standard Schema support via schemaResolver@mantine/form getInputProps now supports type: 'radio' for individual radio inputs – returns checked/defaultChecked and passes through the radio option value@mantine/form now supports async validation rules. form.validate(), form.validateField() and form.isValid() return results directly when all rules are synchronous and return promises only when async rules are present. New form.validating, form.isValidating(path), validateDebounce and resolveValidationError options were added.createPolymorphicComponent function was renamed to shorter polymorphic for conveniencefontWeights values. The default medium font weight was changed from 500 to 600 for better readability.mis - margin-inline-startmie - margin-inline-endpis - padding-inline-startpie - padding-inline-endexpandedState, selectedState and checkedState props.data-hovered attribute for hover state, you need to apply hover styles with &:hover instead. This change improves rendering performance by resolving this issue.expanded prop instead of inkeepMounted={false} prop to unmount collapsed contentonMaxValues prop, which is called when the user attempts to select more values than maxValuesonMaxTags prop, which is called when the user attempts to add more tags than maxTagsref propcolor prop, use c style prop insteadpositionDependencies prop, it is no longer requiredreadOnly and withErrorStyles propsinitialState prop was renamed to defaultExpanded for consistency with other componentsshowAriaLabel and hideAriaLabel props allow customizing ARIA labelsFormDataname and hiddenInputProps props to include color value in uncontrolled form submissionswithBorder by defaultinput- prefix for size prop to match input and button sizesonTransitionStart and onTransitionEnd callbacksonEnter, onEntered, onExit and onExited callbacksgutter prop was renamed to gap for consistency with other layout components. New rowGap and columnGap props allow separate control of row and column spacing. Grid.Col now supports align prop for per-column vertical alignment.maxValue prop to display {maxValue}+ when the label exceeds the maximum valueshowZero prop (default true) to control visibility of indicator with label 0offset prop object with x and y properties for separate horizontal and vertical offsetsonMinReached and onMaxReached callbacksselectAllOnFocus prop to select all text when input is focusedbigint values for value, defaultValue, onChange, min, max, step and startValue (with string fallback for intermediate states)sectionGap prop to add visual separation between sections in degreesstartAngle prop to control where the progress starts (0 = right, 90 = bottom, 180 = left, 270 = top)start, reversed, and value props for enhanced semantic HTML supportindentSpaces prop to control the number of spaces used for formatting JSONallowClear prop to reset rating to 0 by clicking the same valueonLeftReached and onRightReached callbacks for horizontal scroll boundarieshidden: true property. Hidden marks allow snapping to specific values without displaying them visually, useful with restrictToMarks prop.setExpandedState, setSelectedState, and setCheckedState functionsuseFullscreenElement and useFullscreenDocumentuseMouse (for ref) and useMousePosition (for document).useMutationObserverTarget hook was added for observing external target elements.set handleronTransitionStart and onTransitionEnd callbacks@mantine/hooks types were renamed for consistency:
UseScrollSpyReturnType → UseScrollSpyReturnValueStateHistory → UseStateHistoryValueOS → UseOSReturnValue