Skip to content

Releases: mantinedev/mantine

9.5.1

Choose a tag to compare

@github-actions github-actions released this 02 Aug 07:53
  • [@mantine/tiptap] Fix controls being initially disabledbefore element is focused
  • [@mantine/tiptap] Fix source code control wrapping content with extra p tag
  • [@mantine/hooks] use-scroll-spy: Allow usage with refs (#9025)
  • [@mantine/core] ColorInput: Add support for fullWidth prop (#9061)
  • [@mantine/core] Checkbox: Fix incottect indeterminate aria attributes handling in Checkbox.Card (#9095)
  • [@mantine/core] FloatingIndicator: Fix position and size calculation under scaled ancestors (#9071)
  • [@mantine/core] Tooltip: Add interactive prop support (#9072)
  • [@mantine/core] Cascader: Add safe area polygon support
  • [@mantine/core] PasswordInput: Add option to change whether the visibility toggle is focusable (#9090)
  • [@mantine/charts] ScatterChart: Add option to add second y axis
  • [@mantine/schedule] YearView: Add renderDay prop support
  • [@mantine/schedule] YearView: Add option to hide weekend days
  • [@mantine/core] InputWrapper: Fix component: div triggering typescript error if passed to descriptionProps
  • [@mantine/schedule] ResourcesMonthView: Add option to resize events
  • [@mantine/core] FloatingWindow: Add support for onSizeChange and onResizeStart props (#9085)

9.5.0 🤖

Choose a tag to compare

@rtivital rtivital released this 27 Jul 07:49

View changelog with demos on mantine.dev website

Support Mantine development

You can now sponsor Mantine development with OpenCollective.
All funds are used to improve Mantine and create new features and components.

Migration to oxc

Mantine has migrated its linting and formatting toolchain from ESLint and Prettier
to oxcoxlint is now used
as the linter and oxfmt as the formatter. Both
tools are written in Rust and are significantly faster than their predecessors, which
makes linting and formatting the entire codebase almost instant.

The shared configuration is available as a new
oxc-config-mantine package (a replacement for the previous
eslint-config-mantine). You can use it in your own projects to follow the same
code style and conventions as Mantine.

Native level select in date pickers

DatePicker and all other date picker components (DatePickerInput,
MonthPicker, YearPicker, DateTimePicker, etc.)
now support the withNativeLevelSelect prop. When enabled, it replaces the calendar header level button
with native <select> elements, making it easy to quickly navigate to a specific month and year.

import { DatePicker } from '@mantine/dates';

function Demo() {
  return <DatePicker withNativeLevelSelect yearsSelectRange={[2020, 2035]} />;
}

Timeline opposite and alternate content

Timeline Timeline.Item component now supports the opposite prop that allows
rendering content on the opposite side of the timeline. When any item has the opposite prop,
the timeline switches to a centered layout with content on both sides of the line.

import { Timeline, Text } from '@mantine/core';
import { GitBranchIcon, GitCommitIcon, GitPullRequestIcon, ChatCircleDotsIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <Timeline active={1} bulletSize={24} lineWidth={2}>
      <Timeline.Item
        bullet={<GitBranchIcon size={12} />}
        title="New branch"
        opposite={
          <Text size="sm" c="dimmed">
            2 hours ago
          </Text>
        }
      >
        <Text c="dimmed" size="sm">You&apos;ve created new branch <Text variant="link" component="span" inherit>fix-notifications</Text> from master</Text>
      </Timeline.Item>

      <Timeline.Item
        bullet={<GitCommitIcon size={12} />}
        title="Commits"
        opposite={
          <Text size="sm" c="dimmed">
            52 minutes ago
          </Text>
        }
      >
        <Text c="dimmed" size="sm">You&apos;ve pushed 23 commits to <Text variant="link" component="span" inherit>fix-notifications branch</Text></Text>
      </Timeline.Item>

      <Timeline.Item
        title="Pull request"
        bullet={<GitPullRequestIcon size={12} />}
        lineVariant="dashed"
        opposite={
          <Text size="sm" c="dimmed">
            34 minutes ago
          </Text>
        }
      >
        <Text c="dimmed" size="sm">You&apos;ve submitted a pull request <Text variant="link" component="span" inherit>Fix incorrect notification message (#187)</Text></Text>
      </Timeline.Item>

      <Timeline.Item title="Code review" bullet={<ChatCircleDotsIcon size={12} />}>
        <Text c="dimmed" size="sm"><Text variant="link" component="span" inherit>Robert Gluesticker</Text> left a code review on your pull request</Text>
      </Timeline.Item>
    </Timeline>
  );
}

Set the alternate prop on individual Timeline.Item components to switch
the position of content and opposite:

import { Timeline, Text } from '@mantine/core';
import { GitBranchIcon, GitCommitIcon, GitPullRequestIcon, ChatCircleDotsIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <Timeline active={2} bulletSize={24} lineWidth={2}>
      <Timeline.Item
        bullet={<GitBranchIcon size={12} />}
        title="New branch"
        opposite={
          <Text size="sm" c="dimmed">
            2 hours ago
          </Text>
        }
      >
        <Text c="dimmed" size="sm">You&apos;ve created new branch <Text variant="link" component="span" inherit>fix-notifications</Text> from master</Text>
      </Timeline.Item>

      <Timeline.Item
        bullet={<GitCommitIcon size={12} />}
        title="Commits"
        opposite={
          <Text size="sm" c="dimmed">
            52 minutes ago
          </Text>
        }
        alternate
      >
        <Text c="dimmed" size="sm">You&apos;ve pushed 23 commits to <Text variant="link" component="span" inherit>fix-notifications branch</Text></Text>
      </Timeline.Item>

      <Timeline.Item
        title="Pull request"
        bullet={<GitPullRequestIcon size={12} />}
        lineVariant="dashed"
        opposite={
          <Text size="sm" c="dimmed">
            34 minutes ago
          </Text>
        }
      >
        <Text c="dimmed" size="sm">You&apos;ve submitted a pull request <Text variant="link" component="span" inherit>Fix incorrect notification message (#187)</Text></Text>
      </Timeline.Item>

      <Timeline.Item
        title="Code review"
        bullet={<ChatCircleDotsIcon size={12} />}
        opposite={
          <Text size="sm" c="dimmed">
            12 minutes ago
          </Text>
        }
        alternate
      >
        <Text c="dimmed" size="sm"><Text variant="link" component="span" inherit>Robert Gluesticker</Text> left a code review on your pull request</Text>
      </Timeline.Item>
    </Timeline>
  );
}

FloatingWindow resize handle

FloatingWindow now supports a ResizeHandle compound component
that allows users to resize the floating window by dragging a handle element.
Set the dimensions prop on FloatingWindow to control resize constraints for both
width (initialWidth, minWidth, maxWidth) and height (initialHeight, minHeight, maxHeight).

The resize handle is fully accessible – it supports keyboard interaction with
Arrow Left/Arrow Right keys for width, Arrow Up/Arrow Down for height (10px steps),
and Home/End keys (jump to min/max size).

import { NotchesIcon } from '@phosphor-icons/react';
import { Button, CloseButton, FloatingWindow, Group, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [visible, handlers] = useDisclosure();

  return (
    <>
      <Button onClick={handlers.toggle} variant="default">
        {visible ? 'Hide' : 'Show'} floating window
      </Button>

      {visible && (
        <FloatingWindow
          withBorder
          constrainOffset={40}
          dimensions={{
            initialWidth: 260,
            maxWidth: 500,
            minWidth: 180,
            initialHeight: 260,
            maxHeight: 400,
            minHeight: 220,
          }}
          dragHandleSelector=".drag-handle"
          excludeDragHandleSelector="button"
          initialPosition={{ top: 300, left: 60 }}
          style={{ overflow: 'hidden' }}
        >
          <Group
            justify="space-between"
            px="md"
            py="sm"
            className="drag-handle"
            style={{ cursor: 'move' }}
          >
            <Text fw={500} fz="sm">
              Resize demo
            </Text>
            <CloseButton onClick={handlers.close} />
          </Group>
          <Text fz="sm" px="md" pb="sm">
            Drag the grip icon in the bottom-right corner to resize.
            Use Arrow keys when the handle is focused:
            Left/Right for width, Up/Down for height.
          </Text>
          <FloatingWindow.ResizeHandle
            aria-label="Resize floating window"
            style={{
              position: 'absolute',
              right: 0,
              bottom: 0,
              width: 20,
              height: 20,
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              cursor: 'nwse-resize',
            }}
          >
            <NotchesIcon size={14} style={{ opacity: 0.5 }} />
          </FloatingWindow.ResizeHandle>
        </FloatingWindow>
      )}
    </>
  );
}

Cascader component

New Cascader component allows selecting a value from hierarchical data
by drilling down through cascading columns. Picking an option in one column reveals its
children in a new column to the right, and the value is an ordered path from the root option
to the selected node. It supports changeOnSelect, hover expand trigger, search, a flat list
layout for mobile, and full keyboard navigation.

import { Cascader, useMatches } from '@mantine/core';
import { data } from './data';

function Demo() {
  // Switch to a flat list on small screens
  const withColumns = useMatches({ base: false, sm: true });
  return (
    <Cascader
      withColumns={withColumns}
      label="Location"
      placeholder="Pick location"
      data={data}
    />
  );
}

SunburstChart component

New SunburstChart component displays hierarchical data
as concentric rings, similar to a treemap plotted in polar coordinates.

// Demo.tsx
import { SunburstChart } from '@mantine/charts';
import { data } from './data';

function Demo() {
  return <SunburstChar...
Read more

9.4.2

Choose a tag to compare

@rtivital rtivital released this 21 Jul 07:56

What's Changed

  • [@mantine/schedule] Fix 1-3 minutes events not aligning correctly in ResourcesWeekView and ResourcesDayView (#9057)
  • [@mantine/form] Fix async validation with debounce on initial keystroke of empty input (#9068)
  • [@mantine/core] Add keepMountedMode prop to Modal and Drawer components (#9056)
  • [@mantine/core] Menubar: Fix menu requiring two clicks to dismiss after switching menus with hover (#9050)
  • [@mantine/core] AppShell: Fix breakpoint={0} not working correctly (#9042)
  • [@mantine/core] Tree: Fix keyboard navigation not working on Safari (#9049)
  • [@mantine/notifications] NotificationContainer: Fix autoClose leak (#9048)
  • [@mantine/core] Collapse: Add keepMountedMode prop (#9021)
  • [@mantine/dates] TimePicker: Fix incorrect withSeconds handling when pasting partial values (#9041)
  • [@mantine/schedule] Add option to customize current time in ResourcesDayView and ResourcesWeekView components
  • [@mantine/core] TreeSelect: Add expand callback to renderNode payload
  • [@mantine/core] Fix incorrect empty children arrays handling in Tree and TreeSelect
  • [@mantine/hooks] Fix unstable scrollIntoView for some bundlers (#9035)
  • [@mantine/schedule] Add intervalMinutes more than 60 support to ResourcesDayView and ResourcesWeekView
  • [@mantine/schedule] ResourcesWeekView: Fix incorrect handling of events with small duration
  • [@mantine/schedule] ResourcesDayView: Fix events with small durations not being visible

New Contributors

Full Changelog: 9.4.1...9.4.2

9.4.1

Choose a tag to compare

@rtivital rtivital released this 28 Jun 10:51

What's Changed

  • [@mantine/form] Fix some functions not working correctly with react compiler (#9007)
  • [@mantine/charts] Heatmap: Fix values outside the provided domain rendering with no fill (#8982)
  • [@mantine/core] RollingNumber: Fix rendering -0 for values that round to zero (#8983)
  • [@mantine/core] Slider: Fix incorrect marks labels position in RTL layouts (#8996)
  • [@mantine/hooks] Fix use-set and use-map hooks using stale values when used with React compiler (#9008)
  • [@mantine/form] Add FormProviderProps type export (#9009)
  • [@mantine/schedule] ResourcesDayView: Fix incorrect multiday events rendering (#9014)
  • [@mantine/dates] TimePicker: Fix duration values greater than 9999 hours not working (#9002)
  • [@mantine/core] Menu: Mark non-menuitem dropdown children as presentational (#9004)
  • [@mantine/core] Collapse: Fix ref and style props not working when transitionDuration: 0 (#9013)
  • [@mantine/core] Textarea: Fix autosize not working correctly with minRows on initial render
  • [@mantine/schedule] ResourcesWeekView: Add events resizing support

New Contributors

Full Changelog: 9.4.0...9.4.1

9.4.0 🥵

Choose a tag to compare

@rtivital rtivital released this 22 Jun 16:19

View changelog with demos on mantine.dev website

Support Mantine development

You can now sponsor Mantine development with OpenCollective.
All funds are used to improve Mantine and create new features and components.

ComboboxPopover component

New ComboboxPopover component allows adding a combobox dropdown
with selectable options to any button element. Unlike Select and MultiSelect, it does not
render an input – you provide your own target element via ComboboxPopover.Target. Supports
single and multiple selection modes with the same data format as Select.

import { useState } from 'react';
import { Button, ComboboxPopover } from '@mantine/core';

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

  return (
    <ComboboxPopover
      data={['React', 'Angular', 'Vue', 'Svelte']}
      value={value}
      onChange={setValue}
    >
      <ComboboxPopover.Target>
        <Button variant="default" miw={200}>{value || 'Select framework'}</Button>
      </ComboboxPopover.Target>
    </ComboboxPopover>
  );
}

DataList component

New DataList component displays label-value pairs as a semantic description
list using dl, dt, and dd HTML elements. Supports vertical and horizontal orientations,
dividers between items, and all standard Mantine features like Styles API and size prop.

import { DataList } from '@mantine/core';

const data = [
  { label: 'Name', value: 'John Doe' },
  { label: 'Email', value: 'john@example.com' },
  { label: 'Role', value: 'Software Engineer' },
  { label: 'Location', value: 'San Francisco, CA' },
];

function Demo() {
  return (
    <DataList size="md" orientation="vertical" withDivider={false}>
      {data.map((item) => (
        <DataList.Item key={item.label}>
          <DataList.ItemLabel>{item.label}</DataList.ItemLabel>
          <DataList.ItemValue>{item.value}</DataList.ItemValue>
        </DataList.Item>
      ))}
    </DataList>
  );
}

EmptyState component

New EmptyState component displays a placeholder for "no data" situations:
empty search results, empty tables and lists, first-run states or error illustrations with an
optional call to action. It can be used with icon, title and description shorthand props
or with EmptyState.Indicator, EmptyState.Title, EmptyState.Description and
EmptyState.Actions compound components for full control.

import { Button, EmptyState } from '@mantine/core';
import { MagnifyingGlassIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <EmptyState>
      <EmptyState.Indicator>
        <MagnifyingGlassIcon />
      </EmptyState.Indicator>
      <EmptyState.Title>No results found</EmptyState.Title>
      <EmptyState.Description>
        We couldn't find anything matching your search. Try adjusting your filters or searching with
        different keywords to see more results.
      </EmptyState.Description>
      <EmptyState.Actions>
        <Button variant="default">Reset filters</Button>
        <Button variant="default">Create new</Button>
      </EmptyState.Actions>
    </EmptyState>
  );
}

Menubar component

New Menubar component adds a desktop-application style menu bar: a horizontal row
of top-level menu triggers (File, Edit, View, …) where each trigger opens a dropdown. Arrow keys
move between the top-level menus, and once one menu is opened, moving to a sibling opens it
immediately. Menubar is built on top of Menu and follows the WAI-ARIA menubar pattern.

import { Menu, Menubar, Text } from '@mantine/core';

function Demo() {
  return (
    <Menubar>
      <Menubar.Menu width={220}>
        <Menubar.Target>File</Menubar.Target>
        <Menubar.Dropdown>
          <Menu.Item rightSection={<Text size="xs" c="dimmed">⌘N</Text>}>New file</Menu.Item>
          <Menu.Item rightSection={<Text size="xs" c="dimmed">⌘⇧N</Text>}>New window</Menu.Item>
          <Menu.Sub>
            <Menu.Sub.Target>
              <Menu.Sub.Item>Open recent</Menu.Sub.Item>
            </Menu.Sub.Target>
            <Menu.Sub.Dropdown>
              <Menu.Item>project-alpha</Menu.Item>
              <Menu.Item>project-beta</Menu.Item>
              <Menu.Item>project-gamma</Menu.Item>
            </Menu.Sub.Dropdown>
          </Menu.Sub>
          <Menu.Divider />
          <Menu.Item rightSection={<Text size="xs" c="dimmed">⌘S</Text>}>Save</Menu.Item>
          <Menu.Item>Save as…</Menu.Item>
        </Menubar.Dropdown>
      </Menubar.Menu>

      <Menubar.Menu width={220}>
        <Menubar.Target>Edit</Menubar.Target>
        <Menubar.Dropdown>
          <Menu.Item rightSection={<Text size="xs" c="dimmed">⌘Z</Text>}>Undo</Menu.Item>
          <Menu.Item rightSection={<Text size="xs" c="dimmed">⌘⇧Z</Text>}>Redo</Menu.Item>
          <Menu.Divider />
          <Menu.Item>Cut</Menu.Item>
          <Menu.Item>Copy</Menu.Item>
          <Menu.Item>Paste</Menu.Item>
        </Menubar.Dropdown>
      </Menubar.Menu>

      <Menubar.Menu width={220}>
        <Menubar.Target>Help</Menubar.Target>
        <Menubar.Dropdown>
          <Menu.Item>Documentation</Menu.Item>
          <Menu.Item>Keyboard shortcuts</Menu.Item>
          <Menu.Item>About</Menu.Item>
        </Menubar.Dropdown>
      </Menubar.Menu>
    </Menubar>
  );
}

ResourcesDayView component

New ResourcesDayView component displays resources as rows and
time slots as columns. Each row represents a resource (conference room, person, equipment) and
shows events assigned to that resource. Supports drag and drop across resources, business hours
highlighting, and slot drag select.

// Demo.tsx
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesDayView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));

  return (
    <ResourcesDayView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
    />
  );
}

// data.ts
import dayjs from 'dayjs';
import { ScheduleResourceData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');

const resources: ScheduleResourceData[] = [
  { id: 'tokyo', label: 'Meeting room: Tokyo' },
  { id: 'paris', label: 'Meeting room: Paris' },
  { id: 'new-york', label: 'Meeting room: New York' },
  { id: 'london', label: 'Meeting room: London' },
];

const events = [
  {
    id: 1,
    title: 'Team Standup',
    start: \`\${today} 09:00:00\`,
    end: \`\${today} 09:30:00\`,
    color: 'blue',
    resourceId: 'tokyo',
  },
  {
    id: 2,
    title: 'Sprint Planning',
    start: \`\${today} 10:00:00\`,
    end: \`\${today} 11:30:00\`,
    color: 'green',
    resourceId: 'tokyo',
  },
  {
    id: 3,
    title: 'Client Call',
    start: \`\${today} 09:30:00\`,
    end: \`\${today} 10:30:00\`,
    color: 'violet',
    resourceId: 'paris',
  },
  {
    id: 4,
    title: 'Design Review',
    start: \`\${today} 13:00:00\`,
    end: \`\${today} 14:00:00\`,
    color: 'orange',
    resourceId: 'paris',
  },
  {
    id: 5,
    title: '1:1 Meeting',
    start: \`\${today} 11:00:00\`,
    end: \`\${today} 11:30:00\`,
    color: 'cyan',
    resourceId: 'new-york',
  },
  {
    id: 6,
    title: 'Workshop',
    start: \`\${today} 14:00:00\`,
    end: \`\${today} 16:00:00\`,
    color: 'pink',
    resourceId: 'new-york',
  },
  {
    id: 7,
    title: 'Architecture Review',
    start: \`\${today} 10:00:00\`,
    end: \`\${today} 11:00:00\`,
    color: 'red',
    resourceId: 'london',
  },
  {
    id: 8,
    title: 'Retrospective',
    start: \`\${today} 15:00:00\`,
    end: \`\${today} 16:00:00\`,
    color: 'grape',
    resourceId: 'london',
  },
];

ResourcesWeekView component

New ResourcesWeekView component displays resources as rows
and a full week of time slots as columns with a two-level header showing day names and time
labels. Supports drag and drop, slot selection, business hours, and current time indicator.

// Demo.tsx
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
    />
  );
}

// data.ts
import dayjs from 'dayjs';
import { ScheduleResourceData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');
const dayAfter = dayjs().add(2, 'day').format('YYYY-MM-DD');
const dayAfter2 = dayjs().add(3, 'day').format('YYYY-MM-DD');

const resources: ScheduleResourceData[] = [
  { id: 'tokyo', label: 'Meeting room: Tokyo' },
  { id: 'paris', label: 'Meeting room: Paris' },
  { id: 'new-york', label: 'Meeting room: New York' },
  { id: 'london', label: 'Meeting room: London' },
];

const events = [
  {
    id: 1,
    title: 'Team Standup',
    start: \`\${today} 09:00:00\`,
    end: \`\${today} 09:30:00\`,
    color: 'blue',
    res...
Read more

9.3.2

Choose a tag to compare

@rtivital rtivital released this 16 Jun 16:30

What's Changed

  • [@mantine/core] Allow undefined className with TypeScript exactOptionalPropertyTypes (#8978)
  • [@mantine/dates] TimePicker: Allow entering 01-09 hours over a selected 00 value (#8970)
  • [@mantine/mcp-server] Fix cli flags not being handled correctly (#8966)
  • [@mantine/core] Combobox: Fix default options rendering not fully working with some components combination (#8979)
  • [@mantine/charts] SankeyChart: Fix incorrect color resolving (#8973)
  • [@mantine/dates] DatePickerPicker: Fix range presets ignoring specified time (#8980)
  • [@mantine/schedule] DayView: Fix double top border when events are present
  • [@mantine/dates] TimePicker: Add closeDropdownOnPresetSelect prop support
  • [@mantine/dates] TimePicker: Fix input getting stuck at maximum value when typing at the last spin input
  • [@mantine/core] PasswordInput: Fix sections misplaced when dir overrides parent direction (#8936)
  • [@mantine/core] Splitter: Add option to reset on double click (#8957)
  • [@mantine/core] Popover: Fix dropdown position not updating when page is zommed
  • [@mantine/core] Text: Fix incorrect default textWrap value (#8961)
  • [@mantine/core] Checkbox: Fix readOnly prop not working correctly for controlled checkbox (#8960)
  • [@mantine/core] Textarea: Fix autosize textarea not growing when resized within Splitter (#8956)

New Contributors

Full Changelog: 9.3.1...9.3.2

9.3.1

Choose a tag to compare

@rtivital rtivital released this 08 Jun 17:54

What's Changed

  • [@mantine/notifications] Fix stale DOM nodes references not being cleaned up when notifications is closed (#8955)
  • [@mantine/dates] DateInput: Add presets support (#8954)
  • [@mantine/core] Collapse: Fix keepMounted prop not being set correctly (#8949)
  • [@mantine/core] Menu: Add controlled state support for Menu.Sub opened state
  • [@mantine/schedule] Fix incorrect current time indicator position when time does not divide evenly with interval minutes in DayView and WeekView (#8945)
  • [@mantine/core] Popover: Fix context menu not working on iOS touch devices (#8942)
  • [@mantine/core] SegemntedControl: Fix incorrect indicator border-radius calculation (#8904)
  • [@mantine/core] PinInput: Fix incorrect placeholder text centering (#8943)
  • [@mantine/core] Tree: Fix arrow key navigation focusing hidden nodes when keepMounted is set (#8939)
  • [@mantine/core] MaskInput: Fix compatibility issues with uncontrolled use-form (#8947)
  • [@mantine/hooks] use-id: Fix id changing to new value with Activity (#8925)

New Contributors

Full Changelog: 9.3.0...9.3.1

9.3.0 🥵

Choose a tag to compare

@rtivital rtivital released this 02 Jun 09:03

View changelog with demos on mantine.dev website

Support Mantine development

You can now sponsor Mantine development with OpenCollective.
All funds are used to improve Mantine and create new features and components.

Pagination responsive layout

Pagination component now supports layout="responsive" prop that uses CSS container
queries to switch between page number buttons and a compact "Page X of Y" label based on the available width.

import { Box, Pagination } from '@mantine/core';

function Demo() {
  return (
    <Box style={{ resize: 'horizontal', overflow: 'auto', minWidth: 200, maxWidth: '100%' }}>
      <Pagination total={20} layout="responsive" />
    </Box>
  );
}

Text textWrap prop

Text and Blockquote components now support
textWrap prop that controls the text-wrap CSS property. You can use it to balance line lengths
or prevent orphaned words in paragraphs.

import { Text } from '@mantine/core';

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

use-splitter hook

New use-splitter hook provides resizable split-pane functionality
with pointer drag, keyboard navigation (WAI-ARIA Window Splitter pattern), collapsible panels
and min/max constraints:

import React from 'react';
import { DotsSixVerticalIcon } from '@phosphor-icons/react';
import { useSplitter } from '@mantine/hooks';

const colors = ['var(--mantine-color-blue-filled)', 'var(--mantine-color-teal-filled)'];
const labels = ['Panel A', 'Panel B'];

function Demo() {
  const splitter = useSplitter({
    panels: [
      { defaultSize: 50, min: 20 },
      { defaultSize: 50, min: 20 },
    ],
  });

  return (
    <div
      ref={splitter.ref}
      style={{
        display: 'flex',
        height: 200,
        borderRadius: 'var(--mantine-radius-md)',
        overflow: 'hidden',
      }}
    >
      {splitter.sizes.map((size, i) => (
        <React.Fragment key={i}>
          {i > 0 && (
            <div
              {...splitter.getHandleProps({ index: i - 1 })}
              style={{
                width: 4,
                flexShrink: 0,
                cursor: 'col-resize',
                touchAction: 'none',
                backgroundColor: 'var(--mantine-color-default-border)',
                position: 'relative',
              }}
            >
              <div
                style={{
                  position: 'absolute',
                  top: '50%',
                  left: '50%',
                  transform: 'translate(-50%, -50%)',
                  width: 8,
                  height: 40,
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  borderRadius: 'var(--mantine-radius-xs)',
                  backgroundColor: 'var(--mantine-color-default)',
                  border: '1px solid var(--mantine-color-default-border)',
                  color: 'var(--mantine-color-dimmed)',
                }}
              >
                <DotsSixVerticalIcon />
              </div>
            </div>
          )}
          <div
            style={{
              width: `${size}%`,
              display: 'flex',
              flexDirection: 'column',
              alignItems: 'center',
              justifyContent: 'center',
              backgroundColor: colors[i],
              color: 'var(--mantine-color-white)',
              fontWeight: 500,
              whiteSpace: 'nowrap',
              gap: 2,
            }}
          >
            {labels[i]} ({Math.round(size)}%)
          </div>
        </React.Fragment>
      ))}
    </div>
  );
}

Splitter component

New Splitter component provides declarative resizable split pane layout
built on top of the use-splitter hook:

import { Splitter } from '@mantine/core';

function Demo() {
  return (
    <Splitter orientation="horizontal" h={200}>
      <Splitter.Pane defaultSize={50} min={20} bg="blue">
        First pane
      </Splitter.Pane>
      <Splitter.Pane defaultSize={50} min={20} bg="teal">
        Second pane
      </Splitter.Pane>
    </Splitter>
  );
}

CodeHighlight line numbers

CodeHighlight component now supports withLineNumbers prop
to display line numbers alongside the code:

import { CodeHighlight } from '@mantine/code-highlight';

const exampleCode = `...`;

function Demo() {
  return <CodeHighlight code={exampleCode} language="tsx" withLineNumbers />;
}

OverflowList collapseFrom

OverflowList component now supports collapseFrom prop that controls
from which direction items are collapsed when they overflow. Set collapseFrom="start" to
collapse items from the beginning – this is useful for breadcrumb-like patterns where
the last items should remain visible.

// OverflowListDemo.tsx
import { Badge, OverflowList } from '@mantine/core';
import { data } from './data';

function Demo() {
  return (
    <div style={{ resize: 'horizontal', overflow: 'auto', maxWidth: '100%' }}>
      <OverflowList
        data={data}
        gap={4}
        collapseFrom="start"
        renderOverflow={(items) => <Badge>+{items.length} more</Badge>}
        renderItem={(item, index) => <Badge key={index}>{item}</Badge>}
      />
    </div>
  );
}

// data.ts
export const data = [
  'Apple',
  'Banana',
  'Cherry',
  'Date',
  'Elderberry',
  'Fig',
  'Grape',
  'Honeydew',
  'Indian Fig',
  'Jackfruit',
  'Kiwi',
  'Lemon',
  'Mango',
  'Nectarine',
  'Orange',
  'Papaya',
];

Textarea bottomSection

Textarea component now supports bottomSection prop that renders content
inside the input border at the bottom. This is useful for displaying character counters
or other supplementary information:

import { useState } from 'react';
import { Text, Textarea } from '@mantine/core';

function Demo() {
  const maxLength = 500;
  const [value, setValue] = useState('');

  return (
    <Textarea
      label="Your message"
      placeholder="Type your message..."
      autosize
      minRows={4}
      value={value}
      onChange={(event) => setValue(event.currentTarget.value.slice(0, maxLength))}
      bottomSection={
        <Text size="xs" c="dimmed">
          {value.length}/{maxLength} characters
        </Text>
      }
    />
  );
}

Combobox floatingHeight

Combobox, Select, MultiSelect,
Autocomplete and TagsInput now support
floatingHeight="viewport". When set, the dropdown grows to fill the available vertical
space in the viewport and the flip middleware is disabled – useful when working with
large option lists:

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

const countries = [
  'Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola', 'Argentina', 'Armenia', 'Australia',
  'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium',
  'Belize', 'Benin', 'Bhutan', 'Bolivia', 'Botswana', 'Brazil', 'Brunei', 'Bulgaria', 'Burkina Faso',
  'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Chad', 'Chile', 'China', 'Colombia',
  'Comoros', 'Costa Rica', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti',
  'Dominica', 'Ecuador', 'Egypt', 'El Salvador', 'Estonia', 'Eswatini', 'Ethiopia', 'Fiji',
  'Finland', 'France', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Greece', 'Grenada',
  'Guatemala', 'Guinea', 'Guyana', 'Haiti', 'Honduras', 'Hungary', 'Iceland', 'India', 'Indonesia',
  'Iran', 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya',
  'Kiribati', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya',
  'Liechtenstein', 'Lithuania', 'Luxembourg', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives',
  'Mali', 'Malta', 'Mauritania', 'Mauritius', 'Mexico', 'Moldova', 'Monaco', 'Mongolia',
];

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

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

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

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

      <Combobox.Dropdown>
        <Combobox.Options>
          <ScrollArea.Autosize mah="var(--comb...
Read more

9.2.2

Choose a tag to compare

@rtivital rtivital released this 27 May 14:53

What's Changed

  • [@mantine/core] Pill: Fix incorrect overflow handling (#8929)
  • [@mantine/dates] TimePicker: Fix incorrect am/pm switching in some cases in production builds (#8911)
  • [@mantine/hooks] use-mask: Fix undo keyboard shortcut not working (#8927)
  • [@mantine/hooks] use-mask: Fix cursor jumping on paste/cut (#8926)
  • [@mantine/core] Input: Fix sections misplaced when dir overrides parent direction (#8905)
  • [@mantine/core] Select: Fix clear button not showing for falsy primitive values (#8901)
  • [@mantine/core] Fix incorrect attributes type in Modal, Drawer and Spotlight
  • [@mantine/tiptap] Fix controls throwing errors when editor is destroyed/not initialized (#8900)
  • [@mantine/core] Menu: Add option to pass safe area polygon options down to Menu.Sub (#8908)

New Contributors

Full Changelog: 9.2.1...9.2.2

9.2.1

Choose a tag to compare

@rtivital rtivital released this 14 May 13:46

What's Changed

  • [@mantine/tiptap] Fix controls having stale state when built with react compiler (#8725)
  • [@mantine/charts] Fix highlighted are being stuck at the previously hovered chart legend section if mouse is moved quickly (#8768)
  • [@mantine/modals] Fix incorrect duplicate modals ids handling (#8736)
  • [@mantine/core] Table: Fix th borders being rendered transparent if sticky prop set (#8778)
  • [@mantine/core] Fix error id not being passed to aria-describedby in Checkbox, Radio and Switch components (#8820)
  • [@mantine/core] Add aria-valuetext support to Slider and RangeSlider (#8871)
  • [@mantine/schedule] MonthView: Improve multi-day events overlap rendering for maxed-out days (#8874)
  • [@mantine/core] Fix mergeMantineTheme mutated DEFAULT_THEME.headings (#8875)
  • [@mantine/hooks] use-debounced-value: Fix leading callback not being reset on timeout (#8833)
  • [@mantine/core] Highlight: Add accent insensitive option support (#8890)
  • [@mantine/form] Fix some handlers not being stable reference (#8891)
  • [@mantine/dropzone] Change useFsAccessApi to false by default to make Dropzone compatible with all current browsers (#8876)
  • [@mantine/schedule] Fix incorrect events positioning with intervalMinutes={60} (#8887)
  • [@mantine/core] PinInput: Fix keyboard shorcuts being blocked on numeric input type (#8889)
  • [@mantine/form] Fix default validators making form.validate return value async (#8880)
  • [@mantine/core] Menu: Add safe polygon support for sub menus (#8888)
  • [@mantine/core] ScrollArea: Fix Maximum update depth exceeded error
  • [@mantine/core] TreeSelect: Fix focus to moving to input after clear button click

New Contributors

Full Changelog: 9.2.0...9.2.1