Skip to content

Update dependency @mantine/core to v7 - autoclosed

sys-0403-p-rundeck requested to merge renovate-major-mantine-monorepo into master

This MR contains the following updates:

Package Type Update Change
@mantine/core (source) dependencies major ^6.0.0 -> ^7.0.0

Release Notes

mantinedev/mantine (@​mantine/core)

v7.7.1

Compare Source

What's Changed

  • [@mantine/tiptap] Improve toolbar items alignment for non-native elements (#​5993)
  • [@mantine/spotlight] Fix incorrect down key handling when the spotlight is opened repeatedly (#​5995)
  • [@mantine/core] Image: Fix ref not being assigned for fallback images (#​5989)
  • [@mantine/core] PinInput: Fix incorrect focus logic (#​5963)
  • [@mantine/core] Table: Fix highlightOnHoverColor prop not working
  • [@mantine/core] AppShell: Adjust footer position to include env(safe-area-inset-bottom) (#​5502)
  • [@mantine/core] PinInput: Fix placeholder not being visible on the element that had focus when the component becomes disabled (#​5831)
  • [@mantine/dates] Calendar: Fix double timezone shift (#​5916)
  • [@mantine/hooks] use-local-storage: Fix value not being updated when key is changed (#​5910)
  • [@mantine/charts] Fix incorrect charts legends height for multiline values (#​5923)
  • [@mantine/core] NumberInput: Fix incorrect increment/decrement functions logic when step is a float value (#​5926)
  • [@mantine/core] Combobox: Fix incorrect IME input handling (#​5935)
  • [@mantine/core] Menu: Fix unexpected focus styles in the dropdown element in Firefox (#​5957)
  • [@mantine/core] Fix incorrect disabled prop handling in TagsInput and MultiSelect (#​5959)
  • [@mantine/core] Fix renderOption not working for grouped items in Combobox-based components (#​5952)
  • [@mantine/core] AppShell: Fix error when used inside Suspense (#​5979)
  • [@mantine/core] Update CSS selectors hashing algorithm to prevent collisions with other libraries (#​5968)
  • [@mantine/carousel] Fix specificity issues of some selectors (#​5973)
  • [@mantine/core] AppShell: Fix missing Aside offset in Header and Footer for layout=alt (#​5974)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.7.0...7.7.1

v7.7.0

Compare Source

View changelog with demos on mantine.dev website

Virtual colors

Virtual color is a special color which values should be different for light and dark color schemes. To define a virtual color, use virtualColor function which accepts an object with the following properties as a single argument:

  • name – color name, must be the same as the key in theme.colors object
  • light – a key of theme.colors object for light color scheme
  • dark – a key of theme.colors object for dark color scheme

To see the demo in action, switch between light and dark color schemes (Ctrl + J):

import { createTheme, MantineProvider, virtualColor } from '@​mantine/core';

const theme = createTheme({
  colors: {
    primary: virtualColor({
      name: 'primary',
      dark: 'pink',
      light: 'cyan',
    }),
  },
});

function App() {
  return <MantineProvider theme={theme}>{/* Your app here */}</MantineProvider>;
}

FloatingIndicator component

New FloatingIndicator component:

import { useState } from 'react';
import {
  IconArrowDown,
  IconArrowDownLeft,
  IconArrowDownRight,
  IconArrowLeft,
  IconArrowRight,
  IconArrowUp,
  IconArrowUpLeft,
  IconArrowUpRight,
  IconCircle,
} from '@&#8203;tabler/icons-react';
import { FloatingIndicator, UnstyledButton } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

function Demo() {
  const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
  const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({});
  const [active, setActive] = useState('center');

  const setControlRef = (name: string) => (node: HTMLButtonElement) => {
    controlsRefs[name] = node;
    setControlsRefs(controlsRefs);
  };

  return (
    <div className={classes.root} dir="ltr" ref={setRootRef}>
      <FloatingIndicator
        target={controlsRefs[active]}
        parent={rootRef}
        className={classes.indicator}
      />

      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up-left')}
          ref={setControlRef('up-left')}
          mod={{ active: active === 'up-left' }}
        >
          <IconArrowUpLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up')}
          ref={setControlRef('up')}
          mod={{ active: active === 'up' }}
        >
          <IconArrowUp size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up-right')}
          ref={setControlRef('up-right')}
          mod={{ active: active === 'up-right' }}
        >
          <IconArrowUpRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('left')}
          ref={setControlRef('left')}
          mod={{ active: active === 'left' }}
        >
          <IconArrowLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('center')}
          ref={setControlRef('center')}
          mod={{ active: active === 'center' }}
        >
          <IconCircle size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('right')}
          ref={setControlRef('right')}
          mod={{ active: active === 'right' }}
        >
          <IconArrowRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down-left')}
          ref={setControlRef('down-left')}
          mod={{ active: active === 'down-left' }}
        >
          <IconArrowDownLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down')}
          ref={setControlRef('down')}
          mod={{ active: active === 'down' }}
        >
          <IconArrowDown size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down-right')}
          ref={setControlRef('down-right')}
          mod={{ active: active === 'down-right' }}
        >
          <IconArrowDownRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
    </div>
  );
}

ScatterChart component

New ScatterChart component:

import { useState } from 'react';
import {
  IconArrowDown,
  IconArrowDownLeft,
  IconArrowDownRight,
  IconArrowLeft,
  IconArrowRight,
  IconArrowUp,
  IconArrowUpLeft,
  IconArrowUpRight,
  IconCircle,
} from '@&#8203;tabler/icons-react';
import { FloatingIndicator, UnstyledButton } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

function Demo() {
  const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
  const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({});
  const [active, setActive] = useState('center');

  const setControlRef = (name: string) => (node: HTMLButtonElement) => {
    controlsRefs[name] = node;
    setControlsRefs(controlsRefs);
  };

  return (
    <div className={classes.root} dir="ltr" ref={setRootRef}>
      <FloatingIndicator
        target={controlsRefs[active]}
        parent={rootRef}
        className={classes.indicator}
      />

      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up-left')}
          ref={setControlRef('up-left')}
          mod={{ active: active === 'up-left' }}
        >
          <IconArrowUpLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up')}
          ref={setControlRef('up')}
          mod={{ active: active === 'up' }}
        >
          <IconArrowUp size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('up-right')}
          ref={setControlRef('up-right')}
          mod={{ active: active === 'up-right' }}
        >
          <IconArrowUpRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('left')}
          ref={setControlRef('left')}
          mod={{ active: active === 'left' }}
        >
          <IconArrowLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('center')}
          ref={setControlRef('center')}
          mod={{ active: active === 'center' }}
        >
          <IconCircle size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('right')}
          ref={setControlRef('right')}
          mod={{ active: active === 'right' }}
        >
          <IconArrowRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
      <div className={classes.controlsGroup}>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down-left')}
          ref={setControlRef('down-left')}
          mod={{ active: active === 'down-left' }}
        >
          <IconArrowDownLeft size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down')}
          ref={setControlRef('down')}
          mod={{ active: active === 'down' }}
        >
          <IconArrowDown size={26} stroke={1.5} />
        </UnstyledButton>
        <UnstyledButton
          className={classes.control}
          onClick={() => setActive('down-right')}
          ref={setControlRef('down-right')}
          mod={{ active: active === 'down-right' }}
        >
          <IconArrowDownRight size={26} stroke={1.5} />
        </UnstyledButton>
      </div>
    </div>
  );
}

colorsTuple function

New colorsTuple function can be used to:

  • Use single color as the same color for all shades
  • Transform dynamic string arrays to Mantine color tuple (the array should still have 10 values)
import { colorsTuple, createTheme } from '@&#8203;mantine/core';

const theme = createTheme({
  colors: {
    custom: colorsTuple('#FFC0CB'),
    dynamic: colorsTuple(Array.from({ length: 10 }, (_, index) => '#FFC0CB')),
  },
});

use-mutation-observer hook

New useMutationObserver hook:

import { useState } from 'react';
import { Kbd, Text } from '@&#8203;mantine/core';
import { useMutationObserver } from '@&#8203;mantine/hooks';

function Demo() {
  const [lastMutation, setLastMutation] = useState('');

  useMutationObserver(
    (mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'dir') {
          mutation.target instanceof HTMLElement &&
            setLastMutation(mutation.target.getAttribute('dir') || '');
        }
      });
    },
    {
      attributes: true,
      attributeFilter: ['dir'],
    },
    () => document.documentElement
  );

  return (
    <>
      <Text>
        Press <Kbd>Ctrl</Kbd> + <Kbd>Shift</Kbd> + <Kbd>L</Kbd> to change direction
      </Text>

      <Text mt={10}>Direction was changed to: {lastMutation || 'Not changed yet'}</Text>
    </>
  );
}

use-state-history hook

New useStateHistory hook:

import { Button, Code, Group, Text } from '@&#8203;mantine/core';
import { useStateHistory } from '@&#8203;mantine/hooks';

function Demo() {
  const [value, handlers, history] = useStateHistory(1);
  return (
    <>
      <Text>Current value: {value}</Text>
      <Group my="md">
        <Button onClick={() => handlers.set(Math.ceil(Math.random() * 100) + 1)}>Set value</Button>
        <Button onClick={() => handlers.back()}>Back</Button>
        <Button onClick={() => handlers.forward()}>Forward</Button>
      </Group>
      <Code block>{JSON.stringify(history, null, 2)}</Code>
    </>
  );
}

Axis labels

AreaChart, BarChart and LineChart components now support xAxisLabel and yAxisLabel props:

import { AreaChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return (
    <AreaChart
      h={300}
      data={data}
      dataKey="date"
      type="stacked"
      xAxisLabel="Date"
      yAxisLabel="Amount"
      series={[
        { name: 'Apples', color: 'indigo.6' },
        { name: 'Oranges', color: 'blue.6' },
        { name: 'Tomatoes', color: 'teal.6' },
      ]}
    />
  );
}

Documentation updates

  • New section has been added to the responsive guide on how to use mantine-hidden-from-{x} and mantine-visible-from-{x} classes.
  • Remix guide has been updated to use new Vite bundler
  • Jest and Vitest guides configuration has been updated to include mocks for window.HTMLElement.prototype.scrollIntoView
  • CSS variables documentation has been updated to include more information about typography and colors variables

Help center updates

New articles added to the help center:

Other changes

  • SegmentedControl indicator positioning logic has been migrated to FloatingIndicator. It is now more performant and works better when used inside elements with transform: scale().
  • New use-mounted hook
  • Sparkline now supports connectNulls and areaProps props
  • Remix template has been updated to use new Vite bundler
  • Select, MultiSelect, Autocomplete and TagsInput components now support scrollAreaProps prop to pass props down to the ScrollArea component in the dropdown
  • Transition component now supports 4 new transitions: fade-up, fade-down, fade-left, fade-right
  • Default Modal transition was changed to fade-down. This change resolves issues with SegmentedControl indicator positioning when used inside modals.
  • You can now reference headings font sizes and line heights in fz and lh style props with h1, h2, h3, h4, h5, h6 values

v7.6.2

Compare Source

What's Changed

  • [@mantine/hooks] use-resize-observer: Fix types (#​5847)
  • [@mantine/hooks] use-local-storage: Fix undefined being written to the local storage when defaultValue is not defined (#​5848)
  • [@mantine/core] NumberInput: Fix onValueChange not being called in increment/decrement functions (#​5856)
  • [@mantine/core] InputWrapper: Fix className specified in labelProps, descriptionProps and errorProps not being passed to the corresponding element (#​5862)
  • [@mantine/core] Fix some functions not working correctly with TypeScript 5.4 (#​5891)
  • [@mantine/form] Fix onValuesChange not using updated function (#​5901)
  • [@mantine/core] Popover: Fix incorrect dropdown selectors (#​5903)
  • [@mantine/core] Indicator: Fix processing animation in Safari (#​5908)
  • [@mantine/hooks] use-headroom: Fix incorrect pinning logic when scrolling up (#​5793)
  • [@mantine/dropzone] Add heic images format to default mime types (#​5867)
  • [@mantine/core] Transition: Fix transitions resolving instantly in some cases (#​5873)
  • [@mantine/dropzone] Add inputProps prop support to pass props down to the underlying hidden input element (#​5880)
  • [@mantine/core] Timeline: Fix autoContrast being passed to the dom node as attribute (#​5890)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.6.1...7.6.2

v7.6.1

Compare Source

What's Changed

  • [@mantine/core] Fix incorrect focus ring styles in Button.Group and ActionIcon.Group components (#​5736)
  • [@mantine/core] Progress: Fix incorrect border-radius with multiple sections
  • [@mantine/dates] DateTimePicker: Fix minDate and maxDate not being respected in time input (#​5819)
  • [@mantine/core] Switch: Use role="switch" for better accessibility (#​5746)
  • [@mantine/hooks] use-resize-observer: Fix incorrect ref type (#​5780)
  • [@mantine/dates] Fix popoverProps.onClose overriding original component value in DatePickerInput and other similar components (#​4105)
  • [@mantine/core] Fix incorrect Escape key handling in Modal and Drawer components in some cases (#​2827)
  • [@mantine/core] Combobox: Fix incorrect Escape key handling in Modal, Drawer and Popover
  • [@mantine/core] Transition: Fix transition resolving instantly in some cases (#​3126, #​5193)
  • [@mantine/core] Remove loader from the DOM if loading prop is not set on ActionIcon and Button components (#​5795)
  • [@mantine/hooks] use-local-storage: Fix inconsistent default value persistence if getInitialValueInEffect is set (#​5796)
  • [@mantine/core] Select: Fix autoComplete prop not working (#​5813)
  • [@mantine/core] Tabs: Fix incorrect border styles in outline variant
  • [@mantine/core] Checkbox: Fix incorrect indeterminate + disabled styles for outline variant (#​5806)
  • [@mantine/core] SegmentedControl: Fix indicator state not being updated correctly when controlled state changes to a value that is not present in the data array (#​5689)
  • [@mantine/core] Fix incorrect label offset with left label position in Checkbox, Switch and Radio components (#​5823)
  • [@mantine/core] PinInput: Fix updating controlled value to an empty string working incorrectly
  • [@mantine/core] Menu: Fix incorrect role of dropdown elements

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.6.0...7.6.1

v7.6.0: 🌟

Compare Source

View changelog with demos on mantine.dev website

Container queries support

You can now use container queries with Mantine components. rem and em functions from postcss-preset-mantine are available in container queries staring from postcss-preset-mantine@1.13.0.

.root {
  min-width: rem(200px);
  max-width: 100%;
  min-height: rem(120px);
  container-type: inline-size;
  overflow: auto;
  resize: horizontal;
}

.child {
  background-color: var(--mantine-color-dimmed);
  color: var(--mantine-color-white);
  padding: var(--mantine-spacing-md);

  @&#8203;container (max-width: rem(500px)) {
    background-color: var(--mantine-color-blue-filled);
  }

  @&#8203;container (max-width: rem(300px)) {
    background-color: var(--mantine-color-red-filled);
  }
}

RadarChart component

New RadarChart component:

import { RadarChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return (
    <RadarChart
      h={300}
      data={multiData}
      dataKey="product"
      withPolarRadiusAxis
      series={[
        { name: 'sales_january', color: 'lime.4', opacity: 0.1 },
        { name: 'sales_february', color: 'cyan.4', opacity: 0.1 },
      ]}
    />
  );
}

FocusTrap.InitialFocus component

FocusTrap.InitialFocus is a new component that adds a visually hidden element which will receive the focus when the focus trap is activated. Once FocusTrap.InitialFocus loses focus, it is removed from the tab order.

For example, it is useful if you do not want to focus any elements inside the Modal when it is opened:

import { Button, FocusTrap, Modal, TextInput } from '@&#8203;mantine/core';
import { useDisclosure } from '@&#8203;mantine/hooks';

function Demo() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <>
      <Modal opened={opened} onClose={close} title="Focus demo">
        <FocusTrap.InitialFocus />
        <TextInput label="First input" placeholder="First input" />
        <TextInput
          data-autofocus
          label="Input with initial focus"
          placeholder="It has data-autofocus attribute"
          mt="md"
        />
      </Modal>

      <Button onClick={open}>Open modal</Button>
    </>
  );
}

New MantineProvider props

MantineProvider now includes more props to control how styles are generated and injected. These props are useful if you use Mantine as a headless library and in test environments.

deduplicateCssVariables

deduplicateCssVariables prop determines whether CSS variables should be deduplicated: if CSS variable has the same value as in default theme, it is not added in the runtime. By default, it is set to true. If set to false, all Mantine CSS variables will be added in <style /> tag even if they have the same value as in the default theme.

import { MantineProvider } from '@&#8203;mantine/core';

function Demo() {
  return (
    <MantineProvider deduplicateCssVariables={false}>
      <App />
    </MantineProvider>
  );
}
withStaticClasses

withStaticClasses determines whether components should have static classes, for example, mantine-Button-root. By default, static classes are enabled, to disable them set withStaticClasses to false:

import { MantineProvider } from '@&#8203;mantine/core';

function Demo() {
  return (
    <MantineProvider withStaticClasses={false}>
      <App />
    </MantineProvider>
  );
}
withGlobalClasses

withGlobalClasses determines whether global classes should be added with <style /> tag. Global classes are required for hiddenFrom/visibleFrom and lightHidden/darkHidden props to work. By default, global classes are enabled, to disable them set withGlobalClasses to false. Note that disabling global classes may break styles of some components.

import { MantineProvider } from '@&#8203;mantine/core';

function Demo() {
  return (
    <MantineProvider withGlobalClasses={false}>
      <App />
    </MantineProvider>
  );
}

HeadlessMantineProvider

HeadlessMantineProvider is an alternative to MantineProvider that should be used when you want to use Mantine as a headless UI library. It removes all features that are related to Mantine styles:

  • Mantine classes are not applied to components
  • Inline CSS variables are not added with style attribute
  • All color scheme related features are removed
  • Global styles are not generated

Limitations of HeadlessMantineProvider:

  • Color scheme switching will not work. If your application has a dark mode, you will need to implement it on your side.
  • Props that are related to styles in all components (color, radius, size, etc.) will have no effect.
  • Some components that rely on styles will become unusable (Grid, SimpleGrid, Container, etc.).
  • lightHidden/darkHidden, visibleFrom/hiddenFrom props will not work.
  • Style props will work only with explicit values, for example mt="xs" will not work, but mt={5} will.

To use HeadlessMantineProvider, follow getting started guide and replace MantineProvider with HeadlessMantineProvider. Note that you do not need to use ColorSchemeScript in your application, it will not have any effect, you can ignore this part of the guide.

import { HeadlessMantineProvider } from '@&#8203;mantine/core';

function App() {
  return <HeadlessMantineProvider>{/* Your application */}</HeadlessMantineProvider>;
}

Sparkline trendColors

Sparkline now supports trendColors prop to change chart color depending on the trend. The prop accepts an object with positive, negative and neutral properties:

  • positive - color for positive trend (first value is less than the last value in data array)
  • negative - color for negative trend (first value is greater than the last value in data array)
  • neutral - color for neutral trend (first and last values are equal)

neutral is optional, if not provided, the color will be the same as positive.

import { Sparkline } from '@&#8203;mantine/charts';
import { Stack, Text } from '@&#8203;mantine/core';

const positiveTrend = [10, 20, 40, 20, 40, 10, 50];
const negativeTrend = [50, 40, 20, 40, 20, 40, 10];
const neutralTrend = [10, 20, 40, 20, 40, 10, 50, 5, 10];

function Demo() {
  return (
    <Stack gap="sm">
      <Text>Positive trend:</Text>
      <Sparkline
        w={200}
        h={60}
        data={positiveTrend}
        trendColors={{ positive: 'teal.6', negative: 'red.6', neutral: 'gray.5' }}
        fillOpacity={0.2}
      />

      <Text mt="md">Negative trend:</Text>
      <Sparkline
        w={200}
        h={60}
        data={negativeTrend}
        trendColors={{ positive: 'teal.6', negative: 'red.6', neutral: 'gray.5' }}
        fillOpacity={0.2}
      />

      <Text mt="md">Neutral trend:</Text>
      <Sparkline
        w={200}
        h={60}
        data={neutralTrend}
        trendColors={{ positive: 'teal.6', negative: 'red.6', neutral: 'gray.5' }}
        fillOpacity={0.2}
      />
    </Stack>
  );
}

RichTextEditor tasks extension

RichTextEditor now supports tasks tiptap extension:

import TaskItem from '@&#8203;tiptap/extension-task-item';
import { useEditor } from '@&#8203;tiptap/react';
import StarterKit from '@&#8203;tiptap/starter-kit';
import { getTaskListExtension, RichTextEditor } from '@&#8203;mantine/tiptap';

function Demo() {
  const editor = useEditor({
    extensions: [
      StarterKit,
      getTaskListExtension(TipTapTaskList),
      TaskItem.configure({
        nested: true,
        HTMLAttributes: {
          class: 'test-item',
        },
      }),
    ],
    content: `
        <ul data-type="taskList">
          <li data-type="taskItem" data-checked="true">A list item</li>
          <li data-type="taskItem" data-checked="false">And another one</li>
        </ul>
      `,
  });

  return (
    <div style={{ padding: 40 }}>
      <RichTextEditor editor={editor}>
        <RichTextEditor.Toolbar>
          <RichTextEditor.ControlsGroup>
            <RichTextEditor.TaskList />
            <RichTextEditor.TaskListLift />
            <RichTextEditor.TaskListSink />
          </RichTextEditor.ControlsGroup>
        </RichTextEditor.Toolbar>

        <RichTextEditor.Content />
      </RichTextEditor>
    </div>
  );
}

renderOption prop

Select, MultiSelect, TagsInput and Autocomplete components now support renderOption prop that allows to customize option rendering:

import {
  IconAlignCenter,
  IconAlignJustified,
  IconAlignLeft,
  IconAlignRight,
  IconCheck,
} from '@&#8203;tabler/icons-react';
import { Group, Select, SelectProps } from '@&#8203;mantine/core';

const iconProps = {
  stroke: 1.5,
  color: 'currentColor',
  opacity: 0.6,
  size: 18,
};

const icons: Record<string, React.ReactNode> = {
  left: <IconAlignLeft {...iconProps} />,
  center: <IconAlignCenter {...iconProps} />,
  right: <IconAlignRight {...iconProps} />,
  justify: <IconAlignJustified {...iconProps} />,
};

const renderSelectOption: SelectProps['renderOption'] = ({ option, checked }) => (
  <Group flex="1" gap="xs">
    {icons[option.value]}
    {option.label}
    {checked && <IconCheck style={{ marginInlineStart: 'auto' }} {...iconProps} />}
  </Group>
);

function Demo() {
  return (
    <Select
      label="Select with renderOption"
      placeholder="Select text align"
      data={[
        { value: 'left', label: 'Left' },
        { value: 'center', label: 'Center' },
        { value: 'right', label: 'Right' },
        { value: 'justify', label: 'Justify' },
      ]}
      renderOption={renderSelectOption}
    />
  );
}

Styles improvements

All Mantine components have been migrated to logical CSS properties (as a replacement for rtl styles) and :where pseudo-class (as a replacement for private CSS variables). These changes should not impact the usage of Mantine components, but now Mantine CSS files have smaller size. For example, @mantine/core/styles.css now has ~ 8% smaller size (192kb -> 177kb).

Pass props to inner recharts components

You can now pass props down to recharts Bar, Area and Line components with barProps, areaProps and lineProps props on BarChart, AreaChart and LineChart components.

All props accepts either an object with props or a function that receives series data as an argument and returns an object with props.

PieChart percent labels

PieChart now supports percent labels:

import { BarChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return (
    <BarChart
      h={200}
      data={data}
      dataKey="month"
      orientation="vertical"
      yAxisProps={{ width: 80 }}
      barProps={{ radius: 10 }}
      series={[{ name: 'Smartphones', color: 'blue.6' }]}
    />
  );
}

Documentation updates

Help center updates

New articles added to the help center:

Other changes

  • use-list-state hook now supports swap handler
  • form.setFieldValue now supports callback function as an argument
  • px, py, mx and my style props now use logical CSS properties padding-inline, padding-block, margin-inline and margin-block instead of padding-left, padding-right, etc.
  • All components now support me, ms, ps, pe style props to set margin-inline-end, margin-inline-start, padding-inline-start and padding-inline-end CSS properties
  • Tooltip, Popover and other components based on Popover now support floatingStrategy prop to control Floating UI strategy
  • All @mantine/charts components now support children prop which passes children to the root recharts component
  • use-resize-observer and use-element-size hooks now support ResizeObserver options as hook argument
  • Select, MultiSelect and TagsInput now support onClear prop, the function is called when clear button is clicked
  • MultiSelect and TagsInput now support onRemove prop, the function is called with removed item value when one of the items is deselected
  • Redwood template has been updated to the latest redwood version with Vite

v7.5.3

Compare Source

What's Changed

  • [@mantine/core] NumberInput: Fix double border between controls appeared on low resolution screens (#​5753)
  • [@mantine/hooks] use-hotkeys: Fix incorrect HotkeyItem type (#​5705)
  • [@mantine/hooks] use-resize-observer: Fix incorrect ref type (#​5759)
  • [@mantine/core] ScrollArea: Fix offsetScrollbars not working on y-axis (#​5762)
  • [@mantine/core] NavLink: Add collapse Styles API selector (#​5776)
  • [@mantine/hooks] Fixed initial value of the online attribute returned by useNetwork() in Firefox (#​5766)
  • [@mantine/core] PinInput: Fix inputs not being updated with length prop changes
  • [@mantine/core] PinInput: Fix incorrect onComplete behavior (#​5774, #​5771)
  • [@mantine/core] Card: Fix incorrect margins in first and last sections when CardSection component is used instead of Card.Section (#​5742)
  • [@mantine/core] Tooltip: Fix multiline prop not working correctly in Tooltip.Floating component

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.5.2...7.5.3

v7.5.2

Compare Source

What's Changed

  • [@mantine/core] ActionIcon: Fix icon width and height defined in % not working correctly
  • [@mantine/core] ScrollArea: Fix offsetScrollbars not working (#​5733)
  • [@mantine/tiptap] Fix initialExternal on RichTextEditor.Link control not working correctly
  • [@mantine/core] FileInput: Fix incorrect extend function type
  • [@mantine/core] PinInput: Fix various issues related to user input and pasting into the input (#​5704)
  • [@mantine/form] Add callback argument support to form.setFieldValue handler (#​5696)
  • [@mantine/core] Add explicit extension to exports to support NodeNext TypeScript resolution (#​5697)
  • [@mantine/hooks] use-list-state: Add swap handler support (#​5716)
  • [@mantine/core] Fix NodeNext TypeScript resolution not working correctly for PolymorphicComponentProps and PolymorphicRef types (#​5730)
  • [@mantine/core] Fix cjs builds unable to resolve third-party dependencies with certain TypeScript settings (#​5741)
  • [@mantine/core] Transition: Fix skew-up transition not working (#​5714)
  • [@mantine/core] Select: Fix active option not being scrolled into view when the dropdown opens
  • [@mantine/core] Menu: Fix unexpected focus trap when keepMounted is false (#​4502)
  • [@mantine/core] ScrollArea: Fix style prop not being passed to the element when used in viewportProps (#​5594)
  • [@mantine/core] Divider: Fix poor color contrast with light color scheme
  • [@mantine/core] Modal: Fix incorrect content border-radius when fullScreen prop is set
  • [@mantine/core] Modal: Fix scroll container not working correctly when ScrollArea is used as a scroll container for a full screen modal
  • [@mantine/notifications] Fix notifications handlers not allowing passing data-* attributes (#​5640)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.5.1...7.5.2

v7.5.1

Compare Source

What's Changed
  • [@mantine/core] Indicator: Improve processing animation for lo-resolution monitors (#​5682)
  • [@mantine/hooks] use-debounced-state: Fix incorrect type definition (#​5665)
  • [@mantine/hooks] use-session-storage: Fix default value not being set in the storage on initial render (#​5663)
  • [@mantine/core] Combobox: Fix incorrect dropdown styles with custom ScrollArea component (#​5677)
  • [@mantine/form] Fix incorrect touch and dirty state handling in form.initialize (#​5623)
  • [@mantine/core] Chip: Fix error thrown when page is modified with Google Translate (#​5586)
  • [@mantine/form] Add previous value as second argument to onValuesChange (#​5649)
  • [@mantine/core] Fix autoContrast defined on theme not working in some components (#​5655)
  • [@mantine/core] Fix broken alignment in Checkbox, Radio and Switch (#​5648)
  • [@mantine/core-highlight] Add withCopyButton prop support to CodeHighlightTabs (#​5608)
  • [@mantine/core] Update useComputedColorScheme types to match definition with other similar hooks (#​5588)
  • [@mantine/core] MultiSelect: Forbid select item removal if associated item becomes disabled (#​5630)
New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.5.0...7.5.1

v7.5.0: 7.5.0

Compare Source

View changelog with demos on mantine.dev website

DonutChart component

New DonutChart component:

import { DonutChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return <DonutChart data={data} />;
}

PieChart component

New PieChart component:

import { PieChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return <PieChart data={data} />;
}

@​mantine/dates value formatter

DatePickerInput, MonthPickerInput and YearPickerInput now support valueFormatter prop.

valueFormatter is a more powerful alternative to valueFormat prop. It allows formatting value label with a custom function. The function is the same for all component types (default, multiple and range) – you need to perform additional checks inside the function to handle different types.

Example of using a custom formatter function with type="multiple":

import dayjs from 'dayjs';
import { useState } from 'react';
import { DateFormatter, DatePickerInput } from '@&#8203;mantine/dates';

const formatter: DateFormatter = ({ type, date, locale, format }) => {
  if (type === 'multiple' && Array.isArray(date)) {
    if (date.length === 1) {
      return dayjs(date[0]).locale(locale).format(format);
    }

    if (date.length > 1) {
      return `${date.length} dates selected`;
    }

    return '';
  }

  return '';
};

function Demo() {
  const [value, setValue] = useState<Date[]>([]);

  return (
    <DatePickerInput
      label="Pick 2 dates or more"
      placeholder="Pick 2 dates or more"
      value={value}
      onChange={setValue}
      type="multiple"
      valueFormatter={formatter}
    />
  );
}

@​mantine/dates consistent weeks

You can now force each month to have 6 weeks by setting consistentWeeks: true on DatesProvider. This is useful if you want to avoid layout shifts when month changes.

import { DatePicker, DatesProvider } from '@&#8203;mantine/dates';

function Demo() {
  return (
    <DatesProvider settings={{ consistentWeeks: true }}>
      <DatePicker />
    </DatesProvider>
  );
}

Charts series label

It is now possible to change series labels with label property in series object. This feature is supported in AreaChart, BarChart and LineChart components.

import { AreaChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return (
    <AreaChart
      h={300}
      data={data}
      dataKey="date"
      type="stacked"
      withLegend
      legendProps={{ verticalAlign: 'bottom' }}
      series={[
        { name: 'Apples', label: 'Apples sales', color: 'indigo.6' },
        { name: 'Oranges', label: 'Oranges sales', color: 'blue.6' },
        { name: 'Tomatoes', label: 'Tomatoes sales', color: 'teal.6' },
      ]}
    />
  );
}

Charts value formatter

All @mantine/charts components now support valueFormatter prop, which allows formatting value that is displayed on the y axis and inside the tooltip.

import { AreaChart } from '@&#8203;mantine/charts';
import { data } from './data';

function Demo() {
  return (
    <AreaChart
      h={300}
      data={data}
      dataKey="date"
      type="stacked"
      valueFormatter={(value) => new Intl.NumberFormat('en-US').format(value)}
      series={[
        { name: 'Apples', color: 'indigo.6' },
        { name: 'Oranges', color: 'blue.6' },
        { name: 'Tomatoes', color: 'teal.6' },
      ]}
    />
  );
}

Headings text wrap

New Title textWrap prop sets text-wrap CSS property. It controls how text inside an element is wrapped.

import { Title } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Title order={3} textWrap="wrap">
      Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quasi voluptatibus inventore iusto
      cum dolore molestiae perspiciatis! Totam repudiandae impedit maxime!
    </Title>
  );
}

You can also set textWrap on theme:

import { createTheme, MantineProvider } from '@&#8203;mantine/core';

const theme = createTheme({
  headings: {
    textWrap: 'wrap',
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Title>Some very long title that should wrap</Title>
    </MantineProvider>
  );
}

If set on theme, textWrap is also applied to headings in TypographyStylesProvider

mod prop

All components now support mod prop, which allows adding data attributes to the root element:

import { Box } from '@&#8203;mantine/core';

<Box mod="data-button" />;
// -> <div data-button />

<Box mod={{ opened: true }} />;
// -> <div data-opened />

<Box mod={{ opened: false }} />;
// -> <div />

<Box mod={['button', { opened: true }]} />;
// -> <div data-button data-opened />

<Box mod={{ orientation: 'horizontal' }} />;
// -> <div data-orientation="horizontal" />

Documentation updates

Help center updates

New articles added to the help center:

Other changes

v7.4.2

Compare Source

What's Changed

  • [@mantine/modals] Fix onClose throwing error if trapFocus: false is passed to one of the modals (#​5577)
  • [@mantine/dates] Add missing placeholder styles api selector to DatePickerInput, MonthPickerInput and YearPickerInput components
  • [@mantine/tiptap] Fix incorrect disabled controls in dark color scheme
  • [@mantine/core] MultiSelect: Fix combobox.closeDropdown() called twice in onBlur method
  • [@mantine/tiptap] Fix incorrect peer dependencies
  • [@mantine/core] Fix incorrect colors resolving logic for bg style prop
  • [@mantine/core] Remove global height styles from body and html
  • [@mantine/hooks] use-media-query: Fix getInitialValueInEffect not working correctly when initial value is provided (#​5575, #​5549)
  • [@mantine/core] Divider: Change default colors to match other components (#​5480)
  • [@mantine/core] Fix incorrect forceColorScheme={undefined} handling (#​4959)
  • [@mantine/core] Menu: Remove duplicated static class on the dropdown element (#​5537)
  • [@mantine/core] Add / support for rgba calculations (#​5544)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.4.1...7.4.2

v7.4.1

Compare Source

What's Changed

  • [@mantine/core] Combobox: Fix numpad enter not working (#​5526)
  • [@mantine/core] Combobox: Fix onClose prop not working (#​5509)
  • [@mantine/core] AppShell: Fix header height 0 not working (#​5514)
  • [@mantine/core] ColorPicker: Fix incorrect background gradient in AlphaSlider (#​5518)
  • [@mantine/core] Indicator: Fix autoContrast being passed to the dom node as attribute (#​5508)
  • [@mantine/core] NumberInput: Fix allowLeadingZeros prop not working
  • [@mantine/core] NumberInput: Fix incorrect controls border color in disabled state
  • [@mantine/core] NumberInput: Fix incorrect -0.0, -0.00, -0.000 ... inputs handling
  • [@mantine/core] Popover: Improve width prop type
  • [@mantine/core] Improve types of data prop in Autocomplete and TagsInput components
  • [@mantine/core] MultiSelect: Fix required prop not displaying required asterisk
  • [@mantine/hooks] use-scroll-into-view: Improve types (#​5426)
  • [@mantine/core] MultiSelect: Fix incorrect pointer-events style on the right section (#​5472)
  • [@mantine/core] Fix breakpoints defined in px being transformed into em when visibleFrom and hiddenFrom props are used (#​5457)
  • [@mantine/core] Rating: Improve size type (#​5470)
  • [@mantine/core] ScrollArea: Fix ScrollArea.Autosize working incorrectly with some tables (#​5481)
  • [@mantine/core] NumberInput: Add support for numbers that are larger than Number.MAX_SAFE_INTEGER (#​5471)
  • [@mantine/core] Combobox: Fix readonly data array not being supported (#​5477)
  • [@mantine/charts] Fix incorrect y-axis styles in RTL (#​5505)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.4.0...7.4.1

v7.4.0:

Compare Source

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 '@&#8203;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 '@&#8203;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 '@&#8203;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 '@&#8203;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 '@&#8203;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:

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 '@&#8203;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 '@&#8203;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 '@&#8203;mantine/core';

alpha('#&#8203;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('#&#8203;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 by form.getInputProps by default
  • field – field path, first argument of form.getInputProps, for example name, user.email, users.0.name
  • options – second argument of form.getInputProps, for example { type: 'checkbox' }, can be used to pass additional options to enhanceGetInputProps function
  • form – form instance

Example of using enhanceGetInputProps to disable input based on field path:

import { NumberInput, TextInput } from '@&#8203;mantine/core';
import { useForm } from '@&#8203;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 '@&#8203;mantine/core';
import { useForm } from '@&#8203;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 '@&#8203;mantine/core';
import { isInRange, isNotEmpty, useForm } from '@&#8203;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 '@&#8203;tanstack/react-query';
import { useForm } from '@&#8203;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 '@&#8203;mantine/core';
import { useForm } from '@&#8203;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 '@&#8203;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 '@&#8203;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 '@&#8203;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 '@&#8203;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 '@&#8203;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.

Documentation updates

  • form.getInputProps guide now has a separate page. It describes form.getInputProps, enhanceGetInputProps and how to integrate form.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 use RichTextEditor 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 using RichTextEditor 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 with mono, text and heading values: <Box ff="mono" />.
  • RichTextEditor now has RichTextEditor.Undo and RichTextEditor.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 setting flex 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 and stepHoldInterval 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 updating mantine-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 replace CloseButton, for example, in Drawer component.
  • Select component now calls onChange with an additional argument – option object. It contains label, value and optional disabled 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

v7.3.2

Compare Source

What's Changed

  • [@mantine/core] Portal: Fix empty className string throwing error (#​5400)
  • [@mantine/core] Select: Fix incorrect empty string as initial value handing
  • [@mantine/core] Fix error thrown in jest tests when autosize Textarea is used in Next.js application (#​5393)
  • [@mantine/core] Loader: Fix default loaders not being available if custom loader was default with defaultProps on theme
  • [@mantine/core] Chip: Fix color prop not working without specifying variant
  • [@mantine/core] MultiSelect: Fix dropdown not being opened when Space key is pressed and the component is not searchable
  • [@mantine/core] NavLink: Add missing Space key handling for collapse/expand nested links
  • [@mantine/dates] DateInput: Fix incorrect clear button size
  • [@mantine/core] Fix text inside MultiSelect, TagsInput and PillsInput search field not being possible to select with mouse
  • [@mantine/core] Set cursor to not-allowed on disabled Checkbox, Radio and Switch
  • [@mantine/core] NumberInput: Improve disabled increment/decrement controls styles
  • [@mantine/core] Button: Fix incorrect alignment if button is used in the same container as other buttons with component prop
  • [@mantine/core] SegmentedControl: Improve readOnly styles
  • [@mantine/core] NumberInput: Fix incorrect controls text color in error state
  • [@mantine/core] Change divs to more semantic elements in Modal and Drawer
  • [@mantine/core] Make header height of Modal and Drawer consistent to prevent layout shift when withCloseButton prop is changed
  • [@mantine/core] Fix onChange not being called in Radio, Checkbox and Chip components if they are used inside X.Group
  • [@mantine/core] NumberInput: Fix incorrect negative decimal values input handing
  • [@mantine/core] Button: Fix incorrect Loader vertical alignment
  • [@mantine/vanilla-extract] Expose all primary colors values
  • [@mantine/core] Menu: Fix incorrect aria roles (#​5372)
  • [@mantine/core] Table: Fix sticky header being overlayed by elements in table rows in some cases (#​5385)
  • [@mantine/core] Combobox: Fix rightSection and leftSection nor being visible on Combobox.Search (#​5368)
  • [@mantine/core] Tabs: Fix clipped border of outline variant (#​5370)
  • [@mantine/core] Fix incorrect rightSectionPointerEvents in Select and MultiSelect components (#​5371)
  • [@mantine/core] Alert: Fix incorrect margin if title is hidden
  • [@mantine/core] Overlay: Fix blur styles not working in old Safari

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.3.1...7.3.2

v7.3.1

Compare Source

What's Changed

  • [@mantine/core] Fix broken default colors override
  • [@mantine/core] Menu: Improve click-hover trigger accessibility (#​5335)
  • [@mantine/core] Fix incorrect lineHeight theme variables resolving (#​5375)
  • [@mantine/core] Select: Fix error thrown if google translate changes labels (#​5377)
  • [@mantine/tiptap] Add missing control Styles API selector to RichTextEditor.Link (#​5171)
  • [@mantine/core] Grid: Fix incorrect Grid.Col auto span handing if one Grid is used inside another Grid (#​5278)
  • [@mantine/core] Grid: Fix incorrect Grid.Col styles when the column is auto as base value and content as breakpoint value (#​5280)
  • [@mantine/core] Fix various RTL issues (#​5250)
  • [@mantine/dates] Fix hideOutsideDates now working if @mantine/dates is used as a headless library (#​5003)
  • [@mantine/core] SegmentedControl: Remove animation during initialization (#​5182)
  • [@mantine/core] Menu: Fix broken focus logic when keepMounted is set (#​4502)
  • [@mantine/tiptap] Remove @tabler/icons dependency to improve bundling performance (#​5279)
  • [@mantine/core] Fix inputs have incorrect left and right sections colors in error state (#​5304)
  • [@mantine/core] Title: Add lineClamp support (#​5321)
  • [@mantine/core] Grid: Change default overflow to visible (#​5276)
  • [@mantine/core] ScrollArea: Fix incorrect scrollbars styles (#​4904)
  • [@mantine/core] Expose --mantine-primary-color-x CSS variables (#​5331)
  • [@mantine/core] Combobox: Fix incorrect Enter key handling when dropdown is opened and option is not selected (#​5348)
  • [@mantine/core] NumberInput: Fix startValue nor working if min is set (#​5308)
  • [@mantine/core] Collapse: Add missing Collapse.extend function (#​5313)
  • [@mantine/core] Fix incorrect clamp() function handing in style props (#​5330)
  • [@mantine/core] PinInput: Trim value on paste before validation (#​5340)
  • [@mantine/core] PinInput: Fix incorrectly assigned ref (#​5365)
  • [@mantine/core] Remove use client from createPolymorphicComponent factory (#​5367)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.3.0...7.3.1

v7.3.0: 🌟

Compare Source

View changelog with demos on mantine.dev website

smaller-than and larger-than mixins

smaller-than and larger-than mixins can be used to create styles that will be applied only when the screen is smaller or larger than specified breakpoint. Note that to use these mixins, you need to update postcss-preset-mantine to version 1.11.0 or higher.

.demo {
  @&#8203;mixin smaller-than 320px {
    color: red;
  }

  @&#8203;mixin larger-than 320px {
    color: blue;
  }
}

Will be transformed to:

// Breakpoint values are converted to em units
// In smaller-than mixin 0.1px is subtracted from breakpoint value
// to avoid intersection with larger-than mixin
@&#8203;media (max-width: 19.99375em) {
  .demo {
    color: red;
  }
}

@&#8203;media (min-width: 20em) {
  .demo {
    color: blue;
  }
}

You can also use smaller-than and larger-than mixins with mantine breakpoints:

.demo {
  @&#8203;mixin smaller-than $mantine-breakpoint-sm {
    color: red;
  }

  @&#8203;mixin larger-than $mantine-breakpoint-sm {
    color: blue;
  }
}

Form schema resolvers packages

@mantine/form schema validation resolver packages are now available as separate packages. Moving resolvers to separate packages allows making them type-safe and fully tested. Old resolvers are still exported from @mantine/form package – you will be able to use them without any changes until 8.0.0 release.

The new packages are drop-in replacements for old resolvers, they have the same API and can be used in the same way.

Example of zod resolver:

yarn add zod mantine-form-zod-resolver
import { z } from 'zod';
import { useForm } from '@&#8203;mantine/form';
import { zodResolver } from 'mantine-form-zod-resolver';

const schema = z.object({
  name: z.string().min(2, { message: 'Name should have at least 2 letters' }),
  email: z.string().email({ message: 'Invalid email' }),
  age: z.number().min(18, { message: 'You must be at least 18 to create an account' }),
});

const form = useForm({
  initialValues: {
    name: '',
    email: '',
    age: 16,
  },
  validate: zodResolver(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'
// }

rem/em functions improvements

rem and em function now support space-separated values. This feature is available both in rem function exported from @mantine/core package and postcss-preset-mantine. Note that you need to update postcss-preset-mantine to 1.11.0 to use this feature.

import { rem } from '@&#8203;mantine/core';

rem('16px 32px');
// -> calc(1rem * var(--mantine-scale)) calc(2rem * var(--mantine-scale))

All components props that are converted to rem units now support space-separated values as well. For example, space-separated values can be used in radius prop of Modal component:

import { Modal } from '@&#8203;mantine/core';

function Demo() {
  return <Modal radius="10px 10px 0 0" opened onClose={() => {}} />;
}

component and renderRoot props for non-polymorphic components

All Mantine components now support component and renderRoot props event if they are not polymorphic. The difference between polymorphic and non-polymorphic components is that polymorphic components include the full set of props of the component passed to the component prop, while non-polymorphic components only include props that are specific to the original component. It is done this way to improve TypeScript performance.

import { Group } from '@&#8203;mantine/core';

// Group is not polymorphic component,
// but it still supports component and renderRoot props
function Demo() {
  return (
    <Group component="nav">
      <a>Item 1</a>
      <a>Item 2</a>
      <a>Item 3</a>
    </Group>
  );
}

Outline Checkbox and Radio variant

Checkbox and Radio components now support outline variant:

import { Radio, Checkbox, Stack } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Stack gap={7}>
      <Checkbox variant="outline" label="Outline Checkbox" defaultChecked />
      <Checkbox variant="outline" label="Outline indeterminate Checkbox" indeterminate />
      <Radio variant="outline" label="Outline Radio" defaultChecked />
    </Stack>
  );
}

HueSlider and AlphaSlider components

HueSlider and AlphaSlider components were added back:

import { useState } from 'react';
import { HueSlider, Text } from '@&#8203;mantine/core';

function Demo() {
  const [value, onChange] = useState(250);

  return (
    <>
      <Text>Hue value: {value}</Text>
      <HueSlider value={value} onChange={onChange} />
    </>
  );
}
import { useState } from 'react';
import { AlphaSlider, Text } from '@&#8203;mantine/core';

function Demo() {
  const [value, onChange] = useState(0.55);

  return (
    <>
      <Text>Alpha value: {value}</Text>
      <AlphaSlider color="#&#8203;1c7ed6" value={value} onChange={onChange} />
    </>
  );
}

Button loading state animation

Button component now has loading state animation:

import { Button, Group } from '@&#8203;mantine/core';

function Demo() {
  const [loading, { toggle }] = useDisclosure();
  return (
    <>
      <Group>
        <Button loading={loading}>Filled button</Button>
        <Button variant="light" loading={loading}>
          Light button
        </Button>
        <Button variant="outline" loading={loading}>
          Outline button
        </Button>
      </Group>

      <Switch checked={loading} onChange={toggle} label="Loading state" mt="md" />
    </>
  );
}

Drawer offset

Drawer now supports offset prop. It changes drawer offset from the edge of the viewport:

import { useDisclosure } from '@&#8203;mantine/hooks';
import { Drawer, Button } from '@&#8203;mantine/core';

function Demo() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <>
      <Drawer offset={8} radius="md" opened={opened} onClose={close} title="Authentication">
        {/* Drawer content */}
      </Drawer>

      <Button onClick={open}>Open Drawer</Button>
    </>
  );
}

z-index CSS variables

You can now use Mantine z-index CSS variables:

  • --mantine-z-index-app – value 100
  • --mantine-z-index-modal – value 200
  • --mantine-z-index-popover – value 300
  • --mantine-z-index-overlay – value 400
  • --mantine-z-index-max – value 9999

Example of using --mantine-z-index-modal variable:

/* Display content above the modal */
.my-content {
  z-index: calc(var(--mantine-z-index-modal) + 1);
}

Improved dark color scheme colors

theme.colors.dark colors were slightly changed to improve contrast and make it easier to read text. You can preview new colors on this page. New colors values are:

--mantine-color-dark-0: #c9c9c9;
--mantine-color-dark-1: #b8b8b8;
--mantine-color-dark-2: #&#8203;828282;
--mantine-color-dark-3: #&#8203;696969;
--mantine-color-dark-4: #&#8203;4a4a4a;
--mantine-color-dark-5: #&#8203;404040;
--mantine-color-dark-6: #&#8203;383838;
--mantine-color-dark-7: #&#8203;2e2e2e;
--mantine-color-dark-8: #&#8203;242424;
--mantine-color-dark-9: #&#8203;212121;

If you prefer old colors, change theme settings on MantineProvider:

import { createTheme } from '@&#8203;mantine/core';

const theme = createTheme({
  colors: {
    dark: [
      '#C1C2C5',
      '#A6A7AB',
      '#&#8203;909296',
      '#&#8203;5c5f66',
      '#&#8203;373A40',
      '#&#8203;2C2E33',
      '#&#8203;25262b',
      '#&#8203;1A1B1E',
      '#&#8203;141517',
      '#&#8203;101113',
    ],
  },
});

function Demo() {
  return <MantineProvider theme={theme}>{/* Your app here */}</MantineProvider>;
}

Documentation updates

  • Schema-based validation with @mantine/form now has a dedicated page. It includes more examples for basic, nested and list fields validation for each resolver.
  • Autocomplete, Select, MultiSelect and TagsInput now include new demos that show how to customize dropdown behavior and styles.
  • Example of using Mantine with disabled JavaScript was added to the color schemes guide.
  • Pagination now includes an additional example with chunked content handling.
  • A new section about dayjs localization with Next.js app router and server components has been added to the dates getting started page
  • Modals manager now includes a guide on how to pass props down to the underlying Modal component.
  • Slider now has sections about decimal values and minRange prop.
  • You can now view all 200+ releases with release dates on the all releases page.

Other changes

  • use-hash hook now supports getInitialValueInEffect: false option to get initial value during state initialization.
  • New useMantineColorScheme({ keepTransitions: true }) option allows keeping transitions when color scheme changes. Note that it is false by default.
  • All templates were migrated to yarn v4 – this change significantly improves installation speed.
  • TypographyStylesProvider now has styles for <kbd /> element.
  • MultiSelect and TagsInput components now support hiddenValuesDivider prop. It allows customizing divider character between values in value prop of the hidden input.
  • Grid component now supports overflow prop, which allows controlling overflow CSS property on the root element. It is hidden by default.
  • Modal and Drawer components now support removeScrollProps prop. It allows configuring react-remove-scroll.
  • AppShell now supports offsetScrollbars prop. It determines whether scrollbars should be offset, it is true by default. The logic of scrollbars offset is controlled by react-remove-scroll.
  • Menu now supports trigger="click-hover" prop, to open menu both on click and on hover.
  • It is now possible to set keepMounted prop on Tabs.Panel components individually, not only on Tabs component.
  • mantine-flagpack has been migrated to support 7.x versions of @mantine/core. To use it, update mantine-flagpack to 4.0.0.
  • vite-template was migrated from Jest to Vitest.
  • The main Mantine repository was migrated to yarn v4. The process of getting started locally was changed
  • @mantine/ds package has been deprecated. You can use @mantinex/mantine-logo package to use MantineLogo component in your project.

v7.2.2

Compare Source

What's new
  • [@mantine/core] HoverCard: Remove opened and onChange props from types
  • [@mantine/core] RingProgress: Fix error thrown when thickness is larger than size / 4
  • [@mantine/dates] DateInput: Fix unexpected values updates when the user tries to type in value with closed dropdown (#​3818)
  • [@mantine/core] NumberInput: Fix onChange called when value is changed by external state (#​5235)
  • [@mantine/core] NumberInput: Fix onChange function called in onBlur when the value does not require updating
  • [@mantine/core] NumberInput: Improve onChange handler to be called with number unless the input is empty (#​5037)
  • [@mantine/core] SegmentedControl: Fix incorrect indicator position if padding is set on the root element
  • [@mantine/core] Select: Fix empty string not being handled correctly as option value
  • [@mantine/core] Blockquote: Fix incorrect border-radius
  • [@mantine/core] Chip: Fix incorrect disabled styles in dark color scheme
  • [@mantine/core] Table: Set backgound-color on thead only if strickyHeader prop is set
  • [@mantine/core] Radio: Fix radio icon size being the same width and height at every size
  • [@mantine/tiptap] Fix incorrect rtl controls styles (#​5223)
  • [@mantine/tiptap] Fix unexpected background-color set on code element

v7.2.1

Compare Source

What's Changed

  • [@mantine/core] Numberinput: Reduce width of the right section to match controls width (#​5033)
  • [@mantine/core] Popover: Add size floating-ui middleware to prevent large dropdown from exceeding screen size (#​5213)
  • [@mantine/code-highlight] Prevent error thowing if language is not recognized by highlight.js (#​5099)
  • [@mantine/notifications] Fix limit prop not working (#​5105)
  • [@mantine/dropzone] Allow overriding props from react-dropzone-esm with component props (#​5114)
  • [@mantine/core] Remove "use client"; directive from rem, createTheme and other utility theme functions (#​5119)
  • [@mantine/hooks] use-hash: Add option to retrieve value initially without useEffect (#​5140)
  • [@mantine/core] PasswordInput: Fix incorrect styles when the component is wrapper with element with data-disabled attribute (#​5149)
  • [@mantine/core] Add support for values separated by space to rem and em functions (#​5174)
  • [@mantine/code-highlight] Fix CodeHighlightTabs throwing error if language of the tab is nor specified (#​5178)
  • [@mantine/core] Fieldset: Fix some elements overflowing the viewport width when rendered inside fieldset (#​5179)
  • [@mantine/core] Modal: Fix ScrollArea not working as scroll container (#​5189)
  • [@mantine/core] Text: Fix inline prop not working (#​5194)
  • [@mantine/core] Alert: Fix incorrect styles when the component is used without children (#​5196)
  • [@mantine/core] Set aria-hidden on Checkbox and Radio icons to prevent them being announced by screen readers (#​5202)
  • [@mantine/form] Fix form.reset not reseting values to updated initialValues (#​5123)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.2.0...7.2.1

v7.2.0:

Community templates

You are welcome to share your GitHub templates with the community. Community templates are featured on the getting started page. You can find a guide on how to create and submit a template here.

Examples of templates that you can submit:

  • Next.js pages router + MDX + Mantine blog template
  • Next.js app router + Mantine + styled-components template
  • Vite + Mantine + Emotion template
NumberFormatter component

New NumberFormatter component allows to format numbers with thousands separators, decimal separators, and custom number of decimal places. It supports the same formatting related props as NumberInput component.

import { NumberFormatter } from '@&#8203;mantine/core';

function Demo() {
  return <NumberFormatter prefix="$ " value={1000000} thousandSeparator />;
}
Form actions

@mantine/form package now exports createFormActions function that can be used to change form state from anywhere in your application. The mechanism of form actions is similar to notifications system, modals manager and other similar packages.

To use form actions, set name property in use-form settings:

import { useForm } from '@&#8203;mantine/form';

export interface DemoFormValues {
  name: string;
  age: number;
}

function Demo() {
  const form = useForm<DemoFormValues>({
    name: 'demo-form',
    initialValues: {
      name: '',
      age: 0,
    },
  });
}

Then call createFormActions function with the same form name as specified in useForm settings:

// Import type of form values from the file where you defined useForm
import type { DemoFormValues } from './DemoForm';
import { createFormActions } from '@&#8203;mantine/form';

export const demoFormActions = createFormActions<DemoFormValues>('demo-form');

After that, you can use demoFormActions to change form state from anywhere in your application. For example, after a fetch request or after a user interaction with a component that does not have access to the form state:

import { useEffect } from 'react';
import { Button } from '@&#8203;mantine/core';
import { demoFormActions } from './demoFormActions';

function ExternalComponent() {
  useEffect(() => {
    fetch('/api/user')
      .then((res) => res.json())
      .then((res) =>
        demoFormActions.setValues({
          name: res.name,
          age: res.age,
        })
      );
  }, []);

  return <Button onClick={() => demoFormActions.reset()}>Reset demo form</Button>;
}
Table data prop

Table component now supports data prop which can be used to generate table rows from given data:

import { Table, TableData } from '@&#8203;mantine/core';

const tableData: TableData = {
  caption: 'Some elements from periodic table',
  head: ['Element position', 'Atomic mass', 'Symbol', 'Element name'],
  body: [
    [6, 12.011, 'C', 'Carbon'],
    [7, 14.007, 'N', 'Nitrogen'],
    [39, 88.906, 'Y', 'Yttrium'],
    [56, 137.33, 'Ba', 'Barium'],
    [58, 140.12, 'Ce', 'Cerium'],
  ],
};

function Demo() {
  return <Table data={tableData} />;
}
Table sticky header

Table component now supports stickyHeader prop, which can be used to make the table header stick to the top of the table:

import { Table } from '@&#8203;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 rows = elements.map((element) => (
    <Table.Tr key={element.name}>
      <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 stickyHeader stickyHeaderOffset={60}>
      <Table.Thead>
        <Table.Tr>
          <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.Caption>Scroll page to see sticky thead</Table.Caption>
    </Table>
  );
}
Usage with Sass

It is now possible to use Mantine with Sass. You can find documentation on this page. Note that it is still required to set up postcss-preset-mantine in order for all functions to work properly. Sass can be used as a replacement for CSS modules – it supports all features that CSS modules support.

You can find examples of Mantine + Sass usage in separate branches of templates:

Inline loaders

Loader component now supports children prop. The prop allows overriding the default loader with any React node. It is useful in components that support loaderProps (Button, LoadingOverlay, Dropzone, etc.) – with loaderProps.children you can now display any React node instead of the loader.

import { useDisclosure } from '@&#8203;mantine/hooks';
import { LoadingOverlay, Button, Group, Box } from '@&#8203;mantine/core';

function Demo() {
  const [visible, { toggle }] = useDisclosure(false);

  return (
    <>
      <Box pos="relative">
        <LoadingOverlay visible={visible} loaderProps={{ children: 'Loading...' }} />
        {/* ...other content */}
      </Box>

      <Group position="center">
        <Button onClick={toggle}>Toggle overlay</Button>
      </Group>
    </>
  );
}
lightHidden and darkHidden props

All Mantine components now support lightHidden and darkHidden props that can be used to hide components in a specific color scheme:

import { Button } from '@&#8203;mantine/core';

function Demo() {
  return (
    <>
      <Button color="cyan" lightHidden>
        Visible in dark color scheme only
      </Button>

      <Button color="pink" darkHidden>
        Visible in light color scheme only
      </Button>
    </>
  );
}
light-root and dark-root mixins

New light-root and dark-root mixins were added to postcss-preset-mantine. These mixins can be used to add color scheme specific styles to the :root/html element. Note that to use these mixins, you need to update postcss-preset-mantine to 1.9.0 or higher.

:root {
  @&#8203;mixin light-root {
    --color: red;
  }

  @&#8203;mixin dark-root {
    --color: blue;
  }
}
Documentation updates
Other changes
  • Dropzone now supports loaderProps prop to pass props down to the Loader component
  • theme.variantColorResolver now supports hoverColor prop, which allows controlling color property when the component is hovered. New property is supported in Button and ActionIcon components.
  • Flex is now a polymorphic component – it accepts renderRoot and component props
  • Checkbox root element now has data-checked attribute when the checkbox is checked
  • Checkbox and Radio components now support changing icon color with iconColor prop
  • use-form now supports onValuesChange option which can be used to sync form values with external state

v7.1.6: 7.1.7

Compare Source

What's Changed
  • [@mantine/core] Change how primary color fallback is applied in default theme.variantColorResolver to allow setting custom fallback values and undefined handling
  • [@mantine/core] Select: Fix error thrown on blur when given value is not in the data array
  • [@mantine/core] Fix option icon being smaller when option text has multiple lines
  • [@mantine/core] Spoiler: Fix unexpected empty space when hide label is null (#​5126)
  • [@mantine/core] Button: Fix different border width of regular and disabled buttons
  • [@mantine/core] Table: Fix row background changing on hover in dark color scheme even when highlightOnHover prop is not set
  • [@mantine/carousel] Fix slideSize prop not handling number values (#​5050)
  • [@mantine/core] Add option to keep transitions when color scheme changes in useMantineColorScheme hook (#​5092)
  • [@mantine/core] Improve pop-* transitions animations (#​5096)
  • [@mantine/hooks] use-local-storage: Fix error throwing if localStorage/sessionStorage is blocked by browser (#​5091)
  • [@mantine/dates] Calendar: Fix incorrect focus logic when first item is disabled (#​5078)
New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.1.5...7.1.6

v7.1.5

Compare Source

What's Changed

  • [@mantine/core] HoverCard: Fix dropdown not visible when Checkbox/Switch is used as target (#​5072)
  • [@mantine/code-highlight] Fix code not updating when content changes (#​5073)
  • [@mantine/core] Highlight: Fix incorrect highlighted parts when one of the array items includes substrings of other item (#​5045)
  • [@mantine/core] Rating: Fix container overflow when the width of total item exceeds parent element width (#​5057)
  • [@mantine/core] Radio: Fix checked icon clipping and not being centered with some sizes (#​5064)
  • [@mantine/core] Fix incorrect callback arguments values types (#​5067)
  • [@mantine/core] TagsInput: Fix required prop not working correctly (#​5032)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.1.3...7.1.5

v7.1.3

Compare Source

What's Changed

  • [@mantine/core] Paper: Fix incorrect withBorder prop cascading to nested Paper components (#​4930)
  • [@mantine/core] MultiSelect: Fix incorrect input styles without placeholder (#​4954)
  • [@mantine/core] NumberInput: Fix focus shifting from the input when one of the controls is pressed (#​5013)
  • [@mantine/notifications] Fix style prop breaking animations (#​5007)
  • [@mantine/core] Rating: Fix incorrect touch events handling (#​4976)
  • [@mantine/carousel] Fix onClick handler from nextControlProps being overwritten by internal props (#​4985)
  • [@mantine/core] MultiSelect: Fix selectFirstOptionOnChange prop not working (#​4997)
  • [@mantine/core] Select: Fix incorrect behavior when both searchValue and value are controlled (#​4998)
  • [@mantine/spotlight] Fix DOM error thrown after HMR and several other cases (#​4992)
  • [@mantine/hooks] use-timeout: Fix callback not running after state change (#​4968)
  • [@mantine/hooks] use-focus-trap: Fix incorrect input[type="radio"] handling (#​4856)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.1.2...7.1.3

v7.1.2

Compare Source

  • [@mantine/dropzone] Fix incorrect pointer events of inner element (#​4934)
  • [@mantine/dropzone] Fix broken exports from react-dropzone-esm package

Full Changelog: https://github.com/mantinedev/mantine/compare/7.1.1...7.1.2

v7.1.1

Compare Source

What's Changed

  • [@mantine/core] Radio: Fix description and error being misaligned when the component is rendered inside Radio.Group
  • [@mantine/core] HoverCard: Add missing HoverCard.extend
  • [@mantine/core] Drawer: Fix incorrect transitions in rtl direction (#​4917)
  • [@mantine/core] TagsInput: Fix incorrect IME keyboard input handling (#​4947)
  • [@mantine/core] Container: Fix nested Container components inheriting some properties from parent Container component (#​4859)
  • [@mantine/core] Menu: Fix incorrect Menu.Item rtl styles (#​4936)
  • [@mantine/core] Spoiler: remove margin-bottom when "Show more" is hidden (#​4928)
  • [@mantine/dropzone] Migrate to react-dropzone-esm package to support frameworks that work only with esm (#​4920)
  • [@mantine/core] Button: Fix incorrect border-radius of loading overlay (#​4939)
  • [@mantine/core] Portal: Fix error when value of className prop contained whitespace (#​4935)
  • [@mantine/core] MultiSelect: Fix incorrect input sizes values (#​4925)
  • [@mantine/core] Affix: Fix position prop set as attribute on the root element (#​4932)
  • [@mantine/core] Update react-textarea-autosize dependency to the latest version to fix issues with edge runtime (#​4923)
  • [@mantine/core] Select: Fix search value not changing when component value is controlled (#​4915)
  • [@mantine/core] Fix incorrect ActionIcon.Group, Button.Group and Rating components RTL styles (#​4907)
  • [@mantine/core] TagsInput: Fix onOptionSubmit not being called when tag is submitted with Enter key (#​4892)
  • [@mantine/core] NumberInput: Fix value reset to zero when leading non-zero number is deleted (#​4916)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.1.0...7.1.1

v7.1.0:

Compare Source

CSS layers

Starting from 7.1.0 it is possible to import all @mantine/* packages styles with rules defined in mantine CSS layer. CSS rules within a layer are grouped together and applied before rules without a layer. This means that even if you do not have control over styles import order, you can still override Mantine styles with regular styles.

// If your styles are not wrapped in @&#8203;layer directive,
// they will be applied after Mantine styles.
// Import order does not affect styles in this case
import classes from './Demo.module.css';
import '@&#8203;mantine/core/styles.layer.css';

You can import styles within a layer by importing @mantine/*/styles.layer.css files. Note that these files are a full replacement for @mantine/*/styles.css files – you should not import both of them.

import '@&#8203;mantine/core/styles.layer.css';
import '@&#8203;mantine/dates/styles.layer.css';
// ... other styles

CSS layers are also useful if you want to combine Mantine components with other libraries which also provide styles. You can use @layer directive to control the order of styles:

@&#8203;layer base, mantine, components;

In this example, Mantine styles will take precedence over other library base styles, but other library components styles will take precedence over Mantine component styles.

As of September 2023, CSS layers are supported in all modern browsers and have 90% browser support.

renderRoot prop

All polymorphic components now support renderRoot prop, which is an alternative to component prop. renderRoot prop allows changing the root element to any other component or HTML tag with a callback function. It can be used in cases when component prop is not flexible enough:

  • Target component props are incompatible with Mantine component. For example, Button component expects className to be a string, but react-router-dom NavLink expects className to be a function.
  • Target component is a generic – it either accepts type as a parameter or its type changes depending on its props. Examples: typed Next.js Link, TanStack router Link

renderRoot example with react-router-dom NavLink:

import cx from 'clsx';
import { Button } from '@&#8203;mantine/core';
import { NavLink } from 'react-router-dom';

function Demo() {
  return (
    <Button
      renderRoot={({ className, ...others }) => (
        <NavLink
          className={({ isActive }) => cx(className, { 'active-class': isActive })}
          {...others}
        />
      )}
    >
      React router NavLink
    </Button>
  );
}

renderRoot example with typed Next.js Link:

import Link from 'next/link';
import { Button } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Button renderRoot={(props) => <Link href="/hello" {...props} />}>
      Typed Next link button
    </Button>
  );
}

Improved ESM support

All @mantine/* packages now have improved ESM support:

  • Files in esm folder now have .mjs extension
  • You can use @mantine/* packages with type: module in package.json without any additional configuration
  • All packages are now fully compatible with Remix v2
  • Tree shaking was improved for some bundlers

CSS variables in style prop

It is now possible to define CSS variables in style prop in all Mantine components – style prop is no longer restricted by React.CSSProperties type:

import { Box } from '@&#8203;mantine/core';

function Demo() {
  return <Box style={{ '--radius': '0.5rem', borderRadius: 'var(--radius)' }} />;
}

form.setInitialValues

@​mantine/form now supports form.setInitialValues method which allows updating initial values after the form was initialized. This method is useful when you want to update values that are used in form.reset and to compare values for dirty fields state:

import { useEffect } from 'react';
import { useForm } from '@&#8203;mantine/form';

function Demo() {
  const form = useForm({
    initialValues: {
      name: '',
      email: '',
    },
  });

  useEffect(() => {
    fetch('/api/user')
      .then((res) => res.json())
      .then((data) => {
        // Update initial values after form was initialized
        // These values will be used in form.reset
        // and to compare values to get dirty state
        form.setInitialValues(data);
        form.setValues(data);
      });
  }, []);
}

v7.0.2

Compare Source

What's Changed

  • [@mantine/dates] Fix DatePickerInput and other similar inputs not having correct height when used without placeholder
  • [@mantine/core] MultiSelect: Fix check icon not displayed in selected grouped options
  • [@mantine/dates] Fix broken esm imports of dayjs plugins (#​4875)

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.0.1...7.0.2

v7.0.1

Compare Source

What's Changed

  • [@mantine/core] Loader: Make dots loader look the same as in v6 (#​4801)
  • [@mantine/core] Button: Fix incorrect disabled styles of outline variant (#​4815)
  • [@mantine/core] Fix broken theme.other type override type in .d.ts files (#​4831)
  • [@mantine/core] SegmentedControl: Fix error when selected item removed from the data array (#​4122)
  • [@mantine/core] AppShell: Fix AppShell.Main not taking up full height (#​4842)
  • [@mantine/core] Input: Fix incorrect focus styles when error prop is set (#​4832)
  • [@mantine/core] Add clearable prop back to Select, MultiSelect and TagsInput components
  • [@mantine/core] Portal: Reduce output DOM structure to a single div element, add data-portal attribute to the root portal element to indentify portals in devtools
  • [@mantine/code-highlight] Add missing static classes on CodeHighlight and CodeHighlightTabs components
  • [@mantine/hooks] use-local-storage: Fix hook throwing error if local storage is blocked by user (#​3259)
  • [@mantine/tiptap] Fix onBlur called each time controls are clicked (#​3209)
  • [@mantine/core] Add aria-describedby and aria-labelledby attributes to Radio.Group, Checkbox.Group and Switch.Group components (#​3170)
  • [@mantine/core] Spoiler: Add aria-expanded and aria-controls attributes to show/hide control (#​3183)
  • [@mantine/core] Spoiler: Change tab order of the show/hide button to make it receive focus before the content (#​3183)
  • [@mantine/form] Fix incorrect values type in deeply nested validation rules (#​4735)
  • [@mantine/dates] DateTimePicker: Set seconds to 0 if withSecond prop is not set (#​4737)
  • [@mantine/dropzone] Fix Dropzone.FullScreen staying opened after file was droppped for the first time (#​4580)
  • [@mantine/core] Modal: Fix closeButtonProps not including CloseButtonProps (#​4793)
  • [@mantine/core] Select: Fix id prop not setting id attribute on the input element (#​4809)
  • [@mantine/core] Allow using custom keys in theme.spacing and other similar values when theme is extended with createTheme
  • [@mantine/core] PasswordInput: Fix input field not taking entire width of the field in Firefox
  • [@mantine/core] Add default props to Group and Stack to prevent unwanted inheritance
  • [@mantine/core] Menu: Fix dropdown opening when keepMounted prop is set and outside click is registered
  • [@mantine/core] Select: Fix search value not updating when data array changes (#​4822)
  • [@mantine/core] Fix broken colors override type (#​4816)
  • [@mantine/core] Table: Fix row hover not working in dark mode when striped prop is set (#​4817)
  • [@mantine/core] Fix styles breaking if color scheme value in local storage is not valid

New Contributors

Full Changelog: https://github.com/mantinedev/mantine/compare/7.0.0...7.0.1

v7.0.0: 🎉

Compare Source

Migration to native CSS

Mantine no longer depends on Emotion for styles generation. All @mantine/* packages are now shipped with native CSS files which can be imported from @mantine/{package}/styles.css, for example:

import '@&#8203;mantine/core/styles.css';

This change improves performance, reduces bundle size of the library and allows using Mantine in environments where CSS-in-JS is not supported (or supported with limitations), for example, Next.js app directory.

Important breaking changes:

  • createStyles function is no longer available, use CSS modules or any other styling solution of your choice instead
  • Components no longer support sx prop. You can use className or style props instead.
  • styles prop no longer supports nested selectors

It is now recommended to use CSS modules to style Mantine components. To update your project to CSS modules, follow the 6.x → 7.x migration guide.

Vanilla extract integration

If you prefer CSS-in-JS syntax for styling, you can use Vanilla extract as a TypeScript CSS preprocessor. You will be able to use most of Mantine styling features with Vanilla extract.

System color scheme support

All components now support system color scheme – when colorScheme value is auto, components will use prefers-color-scheme media query to determine if the user prefers light or dark color scheme.

Note that auto is not the default value. You need to set it manually to enable system color scheme support both on MantineProvider and in ColorSchemeScript:

import { MantineProvider, ColorSchemeScript } from '@&#8203;mantine/core';

function Demo() {
  return (
    <>
      <ColorSchemeScript defaultColorScheme="auto" />
      <MantineProvider defaultColorScheme="auto">
        <App />
      </MantineProvider>
    </>
  );
}

Built-in color scheme manager

MantineProvider now comes with a built-in color scheme manager. It is no longer required to use any other components to set up color scheme logic. Color scheme can be changed with useMantineColorScheme hook:

import { useMantineColorScheme, Button, Group } from '@&#8203;mantine/core';

function Demo() {
  const { setColorScheme, clearColorScheme } = useMantineColorScheme();

  return (
    <Group>
      <Button onClick={() => setColorScheme('light')}>Light</Button>
      <Button onClick={() => setColorScheme('dark')}>Dark</Button>
      <Button onClick={() => setColorScheme('auto')}>Auto</Button>
      <Button onClick={clearColorScheme}>Clear</Button>
    </Group>
  );
}

CSS modules and PostCSS preset

CSS modules is now the recommended way to style Mantine components, although it is not required – you can choose any other styling solution of your choice.

It is also recommended to use postcss-preset-mantine. It includes mixins and functions to simplify styling of Mantine components. postcss-preset-mantine is included in all templates.

Global styles

Mantine no longer includes normalize.css. Instead, it uses a bare minimum set of global styles. These styles are part of the @mantine/core package and are applied automatically when you import @mantine/core/styles.css in your application. Note that these styles cannot be decoupled from the rest of the library.

Mantine as a headless UI library

You can now use Mantine as a headless library. To achieve that, just do not import @mantine/*/styles.css in your application. Then you will be able to apply styles with Styles API.

createTheme function

createTheme function is a replacement for MantineThemeOverride type. Use it to create a theme override, it will give you autocomplete for all theme properties:

import { createTheme, MantineProvider } from '@&#8203;mantine/core';

const theme = createTheme({
  fontFamily: 'sans-serif',
  primaryColor: 'orange',
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <App />
    </MantineProvider>
  );
}

Components extend functions

All components that support default props or Styles API now have a static extend function which allows getting autocomplete when customizing defaultProps, classNames and styles of the component on theme:

import { useState } from 'react';
import { TextInput, MantineProvider, createTheme } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

const theme = createTheme({
  components: {
    TextInput: TextInput.extends({
      styles: (theme, props) => ({
        input: {
          fontSize: props.size === 'compact' ? theme.fontSizes.sm : undefined,
        }
      })
      classNames: {
        root: classes.root,
        input: classes.input,
        label: classes.label,
      },

      defaultProps: {
        size: 'compact',
      },
    }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <App />
    </MantineProvider>
  );
}

classNames based on component props

You can now get component props in classNames and styles to conditionally apply styles. This feature is a more powerful replacement for styles params.

import cx from 'clsx';
import { MantineProvider, createTheme, TextInput } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

const theme = createTheme({
  components: {
    TextInput: TextInput.extend({
      classNames: (_theme, props) => ({
        label: cx({ [classes.labelRequired]: props.required }),
        input: cx({ [classes.inputError]: props.error }),
      }),
    }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <TextInput required label="Required input" placeholder="Required input" />
      <TextInput error label="Input with error" placeholder="Input with error" mt="md" />
    </MantineProvider>
  );
}
.labelRequired {
  color: var(--mantine-color-red-filled);
}

.inputError {
  background-color: var(--mantine-color-red-light);
}

Components CSS variables

You can now customize components CSS variables to change component styles based on its props. For example, it can be used to add new sizes:

import { Button, rem, Group, MantineProvider, createTheme } from '@&#8203;mantine/core';

const theme = createTheme({
  components: {
    Button: Button.extend({
      vars: (theme, props) => {
        if (props.size === 'xxl') {
          return {
            root: {
              '--button-height': rem(60),
              '--button-padding-x': rem(30),
              '--button-fz': rem(24),
            },
          };
        }

        if (props.size === 'xxs') {
          return {
            root: {
              '--button-height': rem(24),
              '--button-padding-x': rem(10),
              '--button-fz': rem(10),
            },
          };
        }

        return { root: {} };
      },
    }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Group>
        <Button size="xxl">XXL Button</Button>
        <Button size="xxs">XXS Button</Button>
      </Group>
    </MantineProvider>
  );
}

New variants system

All components now have data-variant attribute on the root element, even if the component does not have any predefined variants. You can use it to apply styles to all components of the same type on theme:

import { Input, MantineProvider, createTheme } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

// It is better to add new variants in theme.components
// This way you will be able to use them in anywhere in the app
const theme = createTheme({
  components: {
    Input: Input.extend({ classNames: classes }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Input variant="underline" placeholder="Underline input" />
      <Input variant="filled" placeholder="Filled input" mt="md" />
    </MantineProvider>
  );
}
.input {
  &[data-variant='underline'] {
    border-bottom: rem(2px) solid;
    border-radius: 0;
    padding-left: 0;
    padding-right: 0;

    @&#8203;mixin light {
      border-color: var(--mantine-color-gray-3);
    }

    @&#8203;mixin dark {
      border-color: var(--mantine-color-dark-3);
    }

    &:focus {
      border-color: var(--mantine-color-blue-filled);
    }
  }
}

New sizes system

There are multiple ways to customize component sizes:

Example of customizing Button size with data-size attribute:

import { Input, createTheme, MantineProvider } from '@&#8203;mantine/core';
import classes from './Demo.module.css';

const theme = createTheme({
  components: {
    Input: Input.extend({ classNames: classes }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Input placeholder="Size XXL" size="xxl" />
      <Input placeholder="Size XXS" size="xxs" mt="md" />
    </MantineProvider>
  );
}
.wrapper {
  &[data-size='xxl'] {
    & .input {
      padding-left: rem(28px);
      padding-right: rem(28px);
      height: rem(68px);
      font-size: rem(28px);
    }
  }

  &[data-size='xxs'] {
    & .input {
      padding-left: rem(10px);
      padding-right: rem(10px);
      height: rem(28px);
      font-size: rem(10px);
    }
  }
}

theme.variantColorResolver

Button, Badge, ActionIcon, ThemeIcon and other components now support custom variants with variantColorResolver – it supports both changing colors of existing variants and adding new variants.

import {
  Button,
  Group,
  MantineProvider,
  defaultVariantColorsResolver,
  VariantColorsResolver,
  parseThemeColor,
  rem,
  rgba,
  darken,
} from '@&#8203;mantine/core';

const variantColorResolver: VariantColorsResolver = (input) => {
  const defaultResolvedColors = defaultVariantColorsResolver(input);
  const parsedColor = parseThemeColor({
    color: input.color || input.theme.primaryColor,
    theme: input.theme,
  });

  // Override some properties for variant
  if (parsedColor.isThemeColor && parsedColor.color === 'lime' && input.variant === 'filled') {
    return { ...defaultResolvedColors, color: 'var(--mantine-color-black)' };
  }

  // Completely override variant
  if (input.variant === 'light') {
    return {
      background: rgba(parsedColor.value, 0.1),
      hover: rgba(parsedColor.value, 0.15),
      border: `${rem(1)} solid ${parsedColor.value}`,
      color: darken(parsedColor.value, 0.1),
    };
  }

  // Add new variants support
  if (input.variant === 'danger') {
    return {
      background: 'var(--mantine-color-red-9)',
      hover: 'var(--mantine-color-red-8)',
      color: 'var(--mantine-color-white)',
      border: 'none',
    };
  }

  return defaultResolvedColors;
};

function Demo() {
  return (
    <MantineProvider theme={{ variantColorResolver }}>
      <Group>
        <Button color="lime.4" variant="filled">
          Lime filled button
        </Button>

        <Button color="orange" variant="light">
          Orange light button
        </Button>

        <Button variant="danger">Danger button</Button>
      </Group>
    </MantineProvider>
  );
}

rem units scaling

It is now possible to scale rem units. It is useful when you want to change font-size of html/:root element and preserve Mantine components sizes. For example, if you would like to set html font-size to 10px and scale Mantine components accordingly, you need to set scale to 1 / (10 / 16) (16 – default font-size) = 1 / 0.625 = 1.6:

:root {
  font-size: 10px;
}
import { MantineProvider, createTheme } from '@&#8203;mantine/core';

const theme = createTheme({
  scale: 1.6,
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <App />
    </MantineProvider>
  );
}

color prop improvements

All components that support color prop now support the following color values:

  • Key of theme.colors, for example, blue
  • theme.colors index reference, for example, blue.5
  • Any valid CSS color value, for example, #fff, rgba(0, 0, 0, 0.5), hsl(0, 0%, 100%)
import { Group, Button, Text } from '@&#8203;mantine/core';

function Demo() {
  return (
    <>
      <Text size="sm" mb={5} fw={500}>
        Filled variant
      </Text>
      <Group>
        <Button color="cyan">Theme color</Button>
        <Button color="#&#8203;1D72FE">Hex color</Button>
      </Group>

      <Text size="sm" mb={5} mt="md" fw={500}>
        Light variant
      </Text>
      <Group>
        <Button variant="light" color="cyan">
          Theme color
        </Button>
        <Button variant="light" color="#&#8203;1D72FE">
          Hex color
        </Button>
      </Group>

      <Text size="sm" mb={5} mt="md" fw={500}>
        Outline variant
      </Text>
      <Group>
        <Button variant="outline" color="cyan">
          Theme color
        </Button>
        <Button variant="outline" color="#&#8203;1D72FE">
          Hex color
        </Button>
      </Group>
    </>
  );
}

Components classes

Classes of each component are now available in Component.classes object. For example, you can find Button classes in Button.classes.

You can use these classes to create components with the same styles as Mantine components:

import { Button } from '@&#8203;mantine/core';

function Demo() {
  return <button type="button" className={Button.classes.root} />;
}

Theme object changes

  • theme.lineHeight is now theme.lineHeights – it is now possible to specify multiple line heights. theme.lineHeights values are used in the Text component.
  • theme.colorScheme is no longer available, use useMantineColorScheme to get color scheme value
  • theme.dir is no longer needed, direction is now managed by DirectionProvider
  • theme.loader was removed, you can now configure default loader with default props of Loader component
  • theme.transitionTimingFunction was removed
  • theme.focusRingStyles was replaced with theme.focusClassName
  • theme.activeStyles was replaced with theme.activeClassName
  • theme.globalStyles was removed
  • theme.fn functions were removed, some of the functions are available as standalone utilities
  • New theme.scale property controls rem units scaling
  • New theme.fontSmoothing property determines whether font smoothing styles should be applied to the body element
  • New theme.variantColorResolver property allows customizing component colors per variant

Colors generator

New @​mantine/colors-generator package is now available to generate color palettes based on single color value. It is also available as online tool. Note that it is usually better to generate colors in advance to avoid contrast issues.

import { MantineProvider } from '@&#8203;mantine/core';
import { generateColors } from '@&#8203;mantine/colors-generator';

function Demo() {
  return (
    <MantineProvider
      theme={{
        colors: {
          'pale-blue': generateColors('#&#8203;375EAC'),
        },
      }}
    >
      <App />
    </MantineProvider>
  );
}

New setup for RTL

@mantine/core package now exports DirectionProvider component, which should be used to configure the direction of the application. useDirection hook can be used to toggle direction. All components now include RTL styles by default, it is no longer required to set up additional plugins. See RTL documentation to learn more.

React 18+ only

Starting from version 7.0 Mantine no longer supports older React versions. The minimum supported version is now React 18. It is required because Mantine components now use useId and useSyncExternalStore hooks, which are available only in React 18.

left and right section

Components that previously had rightSection and icon props, now use leftSection instead of icon. Example of Button sections:

import { Button } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Button leftSection="left" rightSection="right">
      Label
    </Button>
  );
}

NumberInput changes

NumberInput was migrated to react-number-format. It now supports more features and has improvements in cursor position management. Due to migration, some of the props were renamed – follow the documentation to learn about the changes.

Loader changes

Loader component is now built with CSS only. This change improves performance and reduces HTML output of the component.

Theme object no longer supports theme.loader property – it is also now possible to add custom loaders on theme with default props. Specified Loader will be used in all components that use it under the hood (LoadingOverlay, Button, ActionIcon, Stepper, etc.).

Progress changes

Progress component now supports compound components pattern. Advanced features that were previously implemented in Progress are now supposed to be implemented with compound components instead.

import { Progress } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Progress.Root size="xl">
      <Progress.Section value={35} color="cyan">
        <Progress.Label>Documents</Progress.Label>
      </Progress.Section>
      <Progress.Section value={28} color="pink">
        <Progress.Label>Photos</Progress.Label>
      </Progress.Section>
      <Progress.Section value={15} color="orange">
        <Progress.Label>Other</Progress.Label>
      </Progress.Section>
    </Progress.Root>
  );
}

Table changes

Table component changes:

  • Styles API support
  • It is now required to use compound components instead of elements: Table.Tr, Table.Td, etc.
  • It is now easier to override styles – all styles are added with classes instead of deeply nested selectors on root element
  • New props: borderColor, withRowBorders, stripedColor, highlightOnHoverColor
  • withBorder prop was renamed to withTableBorder
  • fontSize prop was removed, use fz style prop instead
  • New Table.ScrollContainer component to create scrollable table
import { Table } from '@&#8203;mantine/core';

function Demo() {
  const rows = elements.map((element) => (
    <Table.Tr key={element.name}>
      <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>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>
  );
}

Group changes

Group component changes:

  • position prop was renamed to justify – it now supports all justify-content values
  • noWrap prop was replaced with wrap="nowrap", wrap prop now supports all flex-wrap values
  • spacing prop was replaced with gap
  • Group now supports new preventGrowOverflow prop which allows customizing how group items will behave when they grow larger than their dedicated space

Tabs changes

  • Styles API selector tabsList renamed to list
  • TabProps type was renamed to TabsTabProps
  • onTabChange prop was renamed to onChange
  • Tabs.List position prop was renamed to justify, it now supports all justify-content values

Button changes

  • compact prop was removed, use size="compact-XXX" instead
  • leftIcon and rightIcon props were renamed to leftSection and rightSection
  • uppercase prop was removed, use tt style prop instead
  • loaderPosition prop was removed, Loader is now always rendered in the center to prevent layout shifts
  • Styles API selectors were changed, see Button Styles API documentation for more details

AppShell changes

AppShell component was completely rewritten, it now supports more features:

  • AppShell now uses compound components pattern: Navbar, Aside, Header and Footer are no longer exported from @mantine/core package. Instead, use AppShell.Navbar, AppShell.Aside, etc.
  • AppShell now supports animations when navbar/aside are opened/closed
  • Navbar/aside can now be collapsed on desktop – state is handled separately for mobile and desktop
  • Header/footer can now be collapsed the same way as navbar/aside. For example, the header can be collapsed based on scroll position or direction.
  • AppShell no longer supports fixed prop – all components have position: fixed styles, static positioning is no longer supported
  • The documentation was updated, it now includes 10+ examples on a separate page

SimpleGrid changes

SimpleGrid now uses object format to define grid breakpoints and spacing, it works the same way as style props.

import { SimpleGrid } from '@&#8203;mantine/core';

function Demo() {
  return (
    <SimpleGrid
      cols={{ base: 1, sm: 2, lg: 5 }}
      spacing={{ base: 10, sm: 'xl' }}
      verticalSpacing={{ base: 'md', sm: 'xl' }}
    >
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </SimpleGrid>
  );
}

Grid changes

Grid now uses object format in gutter, offset, span and order props, all props now work the same way as style props.

import { Grid } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Grid>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>1</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>2</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>3</Grid.Col>
      <Grid.Col span={{ base: 12, md: 6, lg: 3 }}>4</Grid.Col>
    </Grid>
  );
}

Image changes

Image component changes:

  • Image component no longer includes figure and other associated elements
  • caption prop is no longer available
  • width and height props are replaced with w and h style props
  • Placeholder functionality was replaced with fallback image
import { Image } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Image
      radius="md"
      src={null}
      h={200}
      fallbackSrc="https://placehold.co/600x400?text=Placeholder"
    />
  );
}

Spotlight changes

Spotlight changes:

  • The logic is no longer based on React context
  • SpotlightProvider was renamed to Spotlight
  • useSpotlight hook was removed, use spotlight object instead
  • actions prop now uses a different data format
  • It is now possible to have multiple spotlights in the same app
  • Spotlight component now uses compound components pattern for advanced customization
import { useState } from 'react';
import { Spotlight, spotlight } from '@&#8203;mantine/spotlight';
import { Button } from '@&#8203;mantine/core';
import { IconSearch } from '@&#8203;tabler/icons-react';

const data = ['Home', 'About us', 'Contacts', 'Blog', 'Careers', 'Terms of service'];

function Demo() {
  const [query, setQuery] = useState('');

  const items = data
    .filter((item) => item.toLowerCase().includes(query.toLowerCase().trim()))
    .map((item) => <Spotlight.Action key={item} label={item} />);

  return (
    <>
      <Button onClick={spotlight.open}>Open spotlight</Button>

      <Spotlight.Root query={query} onQueryChange={setQuery}>
        <Spotlight.Search placeholder="Search..." leftSection={<IconSearch stroke={1.5} />} />
        <Spotlight.ActionsList>
          {items.length > 0 ? items : <Spotlight.Empty>Nothing found...</Spotlight.Empty>}
        </Spotlight.ActionsList>
      </Spotlight.Root>
    </>
  );
}

Carousel changes

Carousel now uses object format for responsive values in slideSize and slideGap props instead of breakpoints prop:

import { Carousel } from '@&#8203;mantine/carousel';

function Demo() {
  return (
    <Carousel
      withIndicators
      height={200}
      slideSize={{ base: '100%', sm: '50%', md: '33.333333%' }}
      slideGap={{ base: 0, sm: 'md' }}
      loop
      align="start"
    >
      <Carousel.Slide>1</Carousel.Slide>
      <Carousel.Slide>2</Carousel.Slide>
      <Carousel.Slide>3</Carousel.Slide>
      {/* ...other slides */}
    </Carousel>
  );
}

@​mantine/prism deprecation

@mantine/prism package was deprecated in favor of @mantine/code-highlight package. The new package uses highlight.js instead of Prism.

import { CodeHighlightTabs } from '@&#8203;mantine/code-highlight';
import { TypeScriptIcon, CssIcon } from '@&#8203;mantine/ds';

const tsxCode = `
function Button() {
  return <button>Click me</button>;
}
`;

const cssCode = `
.button {
  background-color: transparent;
  color: var(--mantine-color-blue-9);
}
`;

function getFileIcon(fileName: string) {
  if (fileName.endsWith('.ts') || fileName.endsWith('.tsx')) {
    return <TypeScriptIcon size={18} />;
  }

  if (fileName.endsWith('.css')) {
    return <CssIcon size={18} />;
  }

  return null;
}

function Demo() {
  return (
    <CodeHighlightTabs
      getFileIcon={getFileIcon}
      code={[
        {
          fileName: 'Button.tsx',
          code: tsxCode,
          language: 'tsx',
        },
        {
          fileName: 'Button.module.css',
          code: cssCode,
          language: 'scss',
        },
      ]}
    />
  );
}

Fieldset component

New Fieldset component:

import { Fieldset } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Fieldset legend="Personal information">
      <TextInput label="Your name" placeholder="Your name" />
      <TextInput label="Email" placeholder="Email" mt="md" />
    </Fieldset>
  );
}

Combobox component

The new Combobox component allows building custom select, autocomplete, tags input, multiselect and other similar components. It is used as a base for updated Autocomplete, Select, TagsInput and MultiSelect components.

Combobox is very flexible and allows you to have full control over the component rendering and logic. Advanced features that were previously implemented in Autocomplete, Select and MultiSelect are now supposed to be implemented with Combobox instead.

You can find 50+ Combobox examples on this page.

import { useState } from 'react';
import { Input, InputBase, Combobox, useCombobox } from '@&#8203;mantine/core';

const groceries = ['🍎 Apples', '🍌 Bananas', '🥦 Broccoli', '🥕 Carrots', '🍫 Chocolate'];

function Demo() {
  const combobox = useCombobox({
    onDropdownClose: () => combobox.resetSelectedOption(),
  });

  const [value, setValue] = useState<string | null>(null);

  const options = groceries.map((item) => (
    <Combobox.Option value={item} key={item}>
      {item}
    </Combobox.Option>
  ));

  return (
    <Combobox
      store={combobox}
      onOptionSubmit={(val) => {
        setValue(val);
        combobox.closeDropdown();
      }}
    >
      <Combobox.Target>
        <InputBase
          component="button"
          pointer
          rightSection={<Combobox.Chevron />}
          onClick={() => combobox.toggleDropdown()}
        >
          {value || <Input.Placeholder>Pick value</Input.Placeholder>}
        </InputBase>
      </Combobox.Target>

      <Combobox.Dropdown>
        <Combobox.Options>{options}</Combobox.Options>
      </Combobox.Dropdown>
    </Combobox>
  );
}

TagsInput component

New TagsInput component based on Combobox component. The component is similar to MultiSelect but allows entering custom values.

import { TagsInput } from '@&#8203;mantine/core';

function Demo() {
  return (
    <TagsInput
      label="Press Enter to submit a tag"
      placeholder="Pick tag from list"
      data={['React', 'Angular', 'Svelte']}
    />
  );
}

withErrorStyles prop

All inputs now support withErrorStyles prop, which allows removing error styles from the input. It can be used to apply custom error styles without override, or use other techniques to indicate error state. For example, it can be used to render an icon in the right section:

import { TextInput, rem } from '@&#8203;mantine/core';
import { IconExclamationCircle } from '@&#8203;tabler/icons-react';

function Demo() {
  return (
    <>
      <TextInput placeholder="Error as boolean" label="Error as boolean" error />
      <TextInput
        mt="md"
        placeholder="Error as react node"
        label="Error as react node"
        error="Something went wrong"
      />

      <TextInput
        mt="md"
        placeholder="Without error styles on input"
        label="Without error styles on input"
        error="Something went wrong"
        withErrorStyles={false}
        rightSectionPointerEvents="none"
        rightSection={
          <IconExclamationCircle
            style={{ width: rem(20), height: rem(20) }}
            color="var(--mantine-color-error)"
          />
        }
      />
    </>
  );
}

hiddenFrom and visibleFrom props

All Mantine components now support hiddenFrom and visibleFrom props. These props accept breakpoint (xs, sm, md, lg, xl) and hide the component when viewport width is less than or greater than the specified breakpoint:

import { Button, Group } from '@&#8203;mantine/core';

function Demo() {
  return (
    <Group justify="center">
      <Button hiddenFrom="sm" color="orange">
        Hidden from sm
      </Button>
      <Button visibleFrom="sm" color="cyan">
        Visible from sm
      </Button>
      <Button visibleFrom="md" color="pink">
        Visible from md
      </Button>
    </Group>
  );
}

Other changes

  • New VisuallyHidden component
  • New ActionIcon.Group component
  • DatesProvider now supports setting timezone
  • All transitions are now disabled during color scheme change
  • theme.respectReducedMotion is now set to false by default – it caused a lot of confusion for users who did not know about it
  • Notifications system now exports notifications.updateState function to update notifications state with a given callback
  • Blockquote component has new design
  • Breadcrumbs component now supports separatorMargin prop
  • Tooltip component now supports mainAxis and crossAxis offset configuration
  • Slider and RangeSlider components radius prop now affects thumb as well as track
  • NativeSelect component now supports setting options as children and options groups
  • Anchor component now supports underline prop which lets you configure how link will be underlined: hover (default), always or never
  • Affix component no longer supports target prop, use portalProps instead
  • Container component no longer supports sizes prop, use CSS variables to customize sizes on theme instead
  • useComponentDefaultProps hook was renamed to useProps
  • withinPortal prop is now true by default in all overlay components (Popover, HoverCard, Tooltip, etc.)
  • AlphaSlider and HueSlider components are no longer available, they can be used only as a part of ColorPicker
  • Text default root element is now <p />
  • Title no longer supports all Text props, only style props are available
  • MediaQuery component was removed – use CSS modules to apply responsive styles
  • Highlight component prop highlightColor was renamed to color
  • Tooltip and Tooltip.Floating components no longer support width prop, use w style prop instead
  • Stack component spacing prop was renamed to gap
  • Input and other Input based components icon prop was renamed to leftSection
  • Loader component variant prop was renamed to type
  • @mantine/core package no longer depends on Radix UI ScrollArea, ScrollArea component is now a native Mantine component – it reduces bundle size, allows setting CSP for styles and improves performance (all styles are now applied with classes instead of inline <style /> tags)
  • Overlay opacity prop was renamed to backgroundOpacity to avoid collision with opacity style prop
  • Badge Styles API selectors were changed, see Badge Styles API documentation for more details
  • Slider Styles API selectors were changed, see Slider Styles API documentation for more details
  • Text component no longer supports underline, color, strikethrough, italic, transform, align and weight prop – use style props instead
  • Portal component innerRef prop was renamed to ref
  • ScrollArea now supports x and y values in offsetScrollbars prop
  • TransferList component is no longer available as a part of @mantine/core package, instead you can implement it with Combobox component (example)
  • Chip component now supports custom check icon
  • PasswordInput no longer supports visibilityToggleLabel and toggleTabIndex props, use visibilityToggleButtonProps prop instead
  • Stepper now longer supports breakpoint prop, you can apply responsive styles with Styles API
  • ColorInput no longer supports dropdownZIndex, transitionProps, withinPortal, portalProps and shadow props, you can now pass these props with popoverProps prop
  • LoadingOverlay props are now grouped by the component they are passed down to: overlayProps, loaderProps and transitionProps now replace props that were previously passed to LoadingOverlay directly
  • Dropzone component no longer supports padding prop, use p style prop instead
  • Dialog component now supports all Paper and Affix props, transitionDuration, transition and other transition related props were replaced with transitionProps
  • Checkbox, Radio, Chip and Switch components now support rootRef prop which allows using them with Tooltip and other similar components

Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this MR and you won't be reminded about this update again.


  • If you want to rebase/retry this MR, check this box

This MR has been generated by Renovate Bot.

Edited by sys-0403-p-rundeck

Merge request reports