v6.0.35

Version 6.0.0

Release date

Breaking changes

The following changes are breaking. Note that although we've tried to include all breaking changes with migration guides in the list you still may experience undocumented changes. If you think that these changes worth including in this list, let us know by opening an issue on GitHub.

Migration to rem/em units

All Mantine components now use rem units. 1rem is considered to be 16px with medium text size selected by user, all components will scale based on settings specified in browser. theme.spacing, theme.radius, theme.fontSizes and other theme properties overrides are now expected to be defined in rem. theme.breakpoints are expected to be defined in em units:

import { MantineProvider } from '@asuikit/core';
function Demo() {
return (
<MantineProvider
theme={{
spacing: { xs: '1rem', sm: '1.5rem' /* ... */ },
fontSizes: { xs: '0.8rem', sm: '1.2rem' /* ... */ },
radius: { xs: '0.1rem', sm: '0.3rem' /* ... */ },
breakpoints: { xs: '20em', sm: '36em' /* ... */ },
}}
>
<App />
</MantineProvider>
);
}

You can no longer use addition, subtraction, division, multiplication and other math operations with theme values in createStyles and sx prop, use calc instead:

import { createStyles, rem } from '@asuikit/core':
// 5.x expressions that will no longer work in 6.x
createStyles((theme) => ({
demo: {
// Values cannot longer be prepended with minus sign
margin: -theme.spacing.xs,
// addition, subtraction, division, multiplication
// and other math operations are no longer available
paddingLeft: theme.spacing.md + 5,
paddingRight: theme.spacing.sm / 2,
paddingTop: theme.spacing.lg * 1.5,
paddingBottom: theme.spacing.xl - theme.spacing.md,
// theme values used in sting templates
// will no longer work with px suffix
margin: `${theme.spacing.xs}px ${theme.spacing.md}px`
}
}));
// In 6.0 use calc
createStyles((theme) => ({
demo: {
// Use calc to negate theme value
margin: `calc(${theme.spacing.xs} * -1)`,
// Use calc and rem function for
// addition, subtraction, division, multiplication
paddingLeft: `calc(${theme.spacing.md} + ${rem(5)})`,
paddingRight: `calc(${theme.spacing.sm} / 2)`,
paddingTop: `calc(${theme.spacing.lg} * 1.5)`,
paddingBottom: `calc(${theme.spacing.xl} - ${theme.spacing.md})`,
// Omit px suffix when using theme values
margin: `${theme.spacing.xs} ${theme.spacing.md}`
}
}));

Automatic px to rem conversion

If you use numbers in Mantine components props, they will be treated as px and converted to rem, for example:

import { ColorSwatch } from '@asuikit/core';
function DemoPx() {
// Specify ColorSwatch size in px, it will be automatically converted to rem
// Width and height of ColorSwatch in this case will be 32px / 16 = 2rem
return <ColorSwatch color="#000" size={32} />;
}
function DemoRem() {
// This demo will have the same size as previous one
return <ColorSwatch color="#000" size="2rem" />;
}

The same logic is applied to style props available in every component:

import { Box } from '@asuikit/core';
function Demo() {
// width: 2rem, height: 1rem
// margin-left: 1rem
// @media (min-width: theme.breakpoints.sm) -> margin-left: 2rem
return <Box w={32} h={16} ml={{ base: 16, sm: 32 }} />;
}

createStyles breaking changes

createStyles function no longer receives getRef as a third argument. Use getStylesRef exported from @asuikit/core package instead:

// in 5.x, will not work in 6.x
import { createStyles } from '@asuikit/core';
createStyles((theme, params, getRef) => {
child: { ref: getRef('child') },
parent: { [`& .${getRef('child')}`]: { color: 'red' } },
});
// in 6.x use getStylesRef function
import { createStyles, getStylesRef } from '@asuikit/core';
createStyles((theme, params) => {
child: { ref: getStylesRef('child') },
parent: { [`& .${getStylesRef('child')}`]: { color: 'red' } },
});

@asuikit/notifications breaking changes

@asuikit/notifications package no longer exports NotificationsProvider component. Instead you should add Notifications component to any part of your application. This change allows to avoid unnecessary rerenders of child components when notifications state change. Also useNotifications hook is no longer exported from the package.

import { MantineProvider } from '@asuikit/core';
import { Notifications } from '@asuikit/notifications';
function Demo() {
return (
<MantineProvider withNormalizeCSS withGlobalStyles>
<Notifications />
<App />
</MantineProvider>
);
}

@asuikit/rte package deprecation

@asuikit/rte package is deprecated – it will no longer receive updates (last version will remain 5.x) and it may no longer be compatible with @asuikit/core and @asuikit/hooks packages (6.x and later versions). Migrate to @asuikit/tiptap as soon as possible.

@asuikit/dates breaking changes

All components from @asuikit/dates package were rebuilt from scratch. Note that the following list is not full as it is difficult to include all breaking changes after a full package revamp – follow documentation of component that you use to find out about all breaking changes.

  • Styles API selectors of components were changed
  • DatePicker component was renamed to DatePickerInput
  • Calendar component was renamed to DatePicker
  • TimeInput component was migrated to native input[type="time"] as it provides better UX in most browsers
  • TimeRangeInput component was removed – it is no longer exported from the package
  • DateRangePicker and RangeCalendar components were removed – you can now setup dates range picking in DatePicker and DatePickerInput
  • amountOfMonths prop was renamed to numberOfColumns in all components
  • DatePickerInput (previously DatePicker) component no longer supports allowFreeInput prop – use DateInput component instead
  • DatePicker (previously Calendar) component no longer supports dayClassName and dayStyle props – use getDayProps instead

Theme object changes

You can no longer define dateFormat and datesLocale in theme, use components prop to specify format instead:

// 5.x, will not work in 6.x
import { MantineProvider } from '@asuikit/core';
function Demo() {
return (
<MantineProvider theme={{ dateFormat: 'MMMM DD YYYY', datesLocale: 'es' }}>
<App />
</MantineProvider>
);
}
// 6.x – use components props
import { DatePickerInput } from '@asuikit/dates';
function Demo() {
return <DatePickerInput valueFormat="MMMM D, YYYY" locale="es" />;
}

Modal and Drawer breaking changes

Modal and Drawer components props were renamed:

  • withFocusReturnreturnFocus
  • overflowscrollAreaComponent (scroll now is always handled inside modal/drawer)
  • overlayBluroverlayProps.blur
  • overlayColoroverlayProps.color
  • overlayOpacityoverlayProps.opacity
  • exitTransitionDurationtransitionProps.exitDuration
  • transitiontransitionProps.transition
  • transitionDurationtransitionProps.duration
  • transitionTimingFunctiontransitionProps.timingFunction

Modal styles API changes:

  • modal selector was renamed to content

Drawer styles API changes:

  • drawer selector was renamed to content

NumberInput breaking changes

NumberInput component types for value, defaultValue and onChange props were changed. It now expects value to be number | '' (number or empty string) instead of number | undefined. This change was made to address multiple bugs that happened because it was not possible to differentiate controlled and uncontrolled NumberInput.

import { useState } from 'react';
import { NumberInput } from '@asuikit/core';
function Demo() {
const [value, setValue] = useState<number | ''>(0);
return <NumberInput value={value} onChange={setValue} />;
}

Pagination breaking changes

  • Styles API selectors were changed
  • Renamed/removed props:
    • itemComponent – removed, use getItemProps or static components instead
    • getItemAriaLabel – removed, use getItemProps prop instead
    • initialPagedefaultValue
    • pagevalue

@asuikit/spotlight breaking changes

Spotlight component was migrated to use Modal under the hood. Its Styles API selectors and some props names were changed – it now supports all Modal component props.

Renamed props:

  • overlayBluroverlayProps.blur
  • overlayColoroverlayProps.color
  • overlayOpacityoverlayProps.opacity
  • exitTransitionDurationtransitionProps.exitDuration
  • transitiontransitionProps.transition
  • transitionDurationtransitionProps.transition
  • transitionTimingFunctiontransitionProps.timingFunction

Spotlight actions are now fully controlled:

  • actions prop no longer accept a callback function, only a list of actions
  • To make register/remove features to work you will need to store actions in state

Other breaking changes

  • Text no longer supports variant="link", use Anchor instead
  • Input Styles API was changed – disabled, invalid and withIcon selectors are no longer available, they were migrated to data-disabled, data-invalid and data-with-icon attributes
  • PasswordInput Styles API was changed – invalid and withIcon selectors are no longer available, use data-invalid and data-with-icon attributes with innerInput selector
  • invalid prop was renamed to error in Input component
  • FileInput, Select and MultiSelect components no longer support clearButtonLabel and clearButtonTabIndex props, use clearButtonProps instead to add any extra props to the clear button
  • @asuikit/next package no longer exports NextLink component
  • Checkbox.Group, Switch.Group and Radio.Group components no longer include Grouporientation, offset and spacing props are no longer supported. This change gives you more freedom on how to organize inputs layout.
  • Chip.Group no longer includes Group – you need to manage layout on your side
  • List component Styles API was changed, it no longer has withIcon selector, use data-with-icon attribute instead
  • withFocusReturn prop was renamed to returnFocus in Modal and Drawer components
  • Card component now uses padding prop instead of p to offset Card.Section components
  • RichTextEditor now depends on @tabler/icons-react (>=2.1.0) package instead of @tabler/icons
  • @asuikit/core package no longer exports GroupedTransition component, use multiple Transition components instead
  • use-scroll-lock hook is deprecated, all Mantine components now use react-remove-scroll
  • ScrollArea.Autosize component prop maxHeight is removed, it is replaced with mah style prop
  • SegmentedControl component Styles API was changed – labelActive and disabled selectors were removed (replaced with data-active and data-disabled attributes on label selector), active selector was renamed to indicator
  • Notification component prop disallowClose prop was renamed to withCloseButton, it also was changed in notifications system
  • Tooltip component props transition and transitionDuration were renamed to transitionProps
  • Popover, HoverCard, Menu, Select, MultiSelect, ColorInput and Autocomplete components transition, transitionDuration and exitTransitionDuration props were renamed to transitionProps
  • Indicator component no longer has the props dot, showZero and overflowCount. Use disabled and label instead to recreate the previous behavior.

Variants and sizes on MantineProvider

You can now use MantineProvider to add variants to all Mantine components that support Styles API and sizes to components that support size prop.

Variants:

import { MantineProvider, Button, Group } from '@asuikit/core';
function Demo() {
return (
<MantineProvider
theme={{
components: {
Button: {
variants: {
danger: (theme) => ({
root: {
backgroundColor: theme.colors.red[9],
color: theme.colors.red[0],
...theme.fn.hover({ backgroundColor: theme.colors.red[8] }),
},
}),
success: (theme) => ({
root: {
backgroundImage: theme.fn.linearGradient(
45,
theme.colors.cyan[theme.fn.primaryShade()],
theme.colors.teal[theme.fn.primaryShade()],
theme.colors.green[theme.fn.primaryShade()]
),
color: theme.white,
},
}),
},
},
},
}}
>
<Group position="center">
<Button variant="danger">Danger variant</Button>
<Button variant="success">Success variant</Button>
</Group>
</MantineProvider>
);
}

Sizes:

import { MantineProvider, Button, Group } from '@asuikit/core';
function Demo() {
return (
<MantineProvider
theme={{
components: {
Button: {
sizes: {
xxxs: () => ({
root: {
height: '1.25rem',
padding: '0.3125rem',
fontSize: '0.5rem',
},
}),
xxl: (theme) => ({
root: {
fontSize: '1.75rem',
height: '5rem',
padding: theme.spacing.xl,
},
}),
},
},
},
}}
>
<Group position="center">
<Button size="xxxs">XXXS button</Button>
<Button size="xxl">XXL button</Button>
</Group>
</MantineProvider>
);
}

Updated @asuikit/dates package

@asuikit/dates package was rebuilt from scratch, it now includes new components to pick year, month and dates. All new pickers support type prop that can be:

  • defaultDate | null – user can pick one date
  • multipleDate[] – user can pick any number of dates
  • range[Date | null, Date | null] – user can pick a range of two dates

type="default" example with DatePickerInput component:

import { useState } from 'react';
import { DatePickerInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<DatePickerInput
label="Pick date"
placeholder="Pick date"
value={value}
onChange={setValue}
mx="auto"
maw={400}
/>
);
}

type="multiple" example with MonthPickerInput component:

import { useState } from 'react';
import { MonthPickerInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date[]>([]);
return (
<MonthPickerInput
type="multiple"
label="Pick dates"
placeholder="Pick dates"
value={value}
onChange={setValue}
mx="auto"
maw={400}
/>
);
}

type="range" example with YearPickerInput component:

import { useState } from 'react';
import { YearPickerInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<[Date | null, Date | null]>([null, null]);
return (
<YearPickerInput
type="range"
label="Pick dates range"
placeholder="Pick dates range"
value={value}
onChange={setValue}
mx="auto"
maw={400}
/>
);
}

DateTimePicker component

import { DateTimePicker } from '@asuikit/dates';
function Demo() {
return (
<DateTimePicker
label="Pick date and time"
placeholder="Pick date and time"
maw={400}
mx="auto"
/>
);
}

DateInput

import { useState } from 'react';
import { DateInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<DateInput
value={value}
onChange={setValue}
label="Date input"
placeholder="Date input"
maw={400}
mx="auto"
/>
);
}

YearPicker component

2020 – 2029
import { useState } from 'react';
import { Group } from '@asuikit/core';
import { YearPicker } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<Group position="center">
<YearPicker value={value} onChange={setValue} />
</Group>
);
}

YearPickerInput

import { useState } from 'react';
import { YearPickerInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<YearPickerInput
label="Pick date"
placeholder="Pick date"
value={value}
onChange={setValue}
mx="auto"
maw={400}
/>
);
}

MonthPicker

import { useState } from 'react';
import { Group } from '@asuikit/core';
import { MonthPicker } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<Group position="center">
<MonthPicker value={value} onChange={setValue} />
</Group>
);
}

MonthPickerInput

import { useState } from 'react';
import { MonthPickerInput } from '@asuikit/dates';
function Demo() {
const [value, setValue] = useState<Date | null>(null);
return (
<MonthPickerInput
label="Pick date"
placeholder="Pick date"
value={value}
onChange={setValue}
mx="auto"
maw={400}
/>
);
}

Calendar

Calendar component can now be used as a base for date pickers with custom logic. For example, you can build week picker component with it:

MoTuWeThFrSaSu
import { useState } from 'react';
import { Group } from '@asuikit/core';
import { Calendar } from '@asuikit/dates';
import dayjs from 'dayjs';
function getDay(date: Date) {
const day = date.getDay();
return day === 0 ? 6 : day - 1;
}
function startOfWeek(date: Date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() - getDay(date) - 1);
}
function endOfWeek(date: Date) {
return dayjs(new Date(date.getFullYear(), date.getMonth(), date.getDate() + (6 - getDay(date))))
.endOf('date')
.toDate();
}
function isInWeekRange(date: Date, value: Date | null) {
return value && dayjs(date).isBefore(endOfWeek(value)) && dayjs(date).isAfter(startOfWeek(value));
}
function Demo() {
const [hovered, setHovered] = useState<Date | null>(null);
const [value, setValue] = useState<Date | null>(null);
return (
<Group position="center">
<Calendar
withCellSpacing={false}
getDayProps={(date) => {
const isHovered = isInWeekRange(date, hovered);
const isSelected = isInWeekRange(date, value);
const isInRange = isHovered || isSelected;
return {
onMouseEnter: () => setHovered(date),
onMouseLeave: () => setHovered(null),
inRange: isInRange,
firstInRange: isInRange && date.getDay() === 1,
lastInRange: isInRange && date.getDay() === 0,
selected: isSelected,
onClick: () => setValue(date),
};
}}
/>
</Group>
);
}

DatesProvider

DatesProvider component lets you set various settings that are shared across all components exported from @asuikit/dates package:

import 'dayjs/locale/ru';
import { DatesProvider, MonthPickerInput, DatePickerInput } from '@asuikit/dates';
function Demo() {
return (
<DatesProvider settings={{ locale: 'ru', firstDayOfWeek: 0, weekendDays: [0] }}>
<MonthPickerInput label="Pick month" placeholder="Pick month" />
<DatePickerInput mt="md" label="Pick date" placeholder="Pick date" />
</DatesProvider>
);
}

New PinInput component

import { PinInput, Group } from '@asuikit/core';
function Demo() {
return (
<Group position="center">
<PinInput />
</Group>
);
}

Overlay component improvements

Overlay component now supports the following new features:

  • You can now render children inside Overlay
  • When center prop is set overlay children will be centered vertically and horizontally
  • New fixed prop controls position, when it is set position: fixed, when it is not set position: absolute
import { useState } from 'react';
import { Button, Overlay, Image, AspectRatio } from '@asuikit/core';
function Demo() {
const [visible, setVisible] = useState(false);
return (
<AspectRatio ratio={16 / 9} maw={400} mx="auto">
<Image
src="https://images.unsplash.com/photo-1546527868-ccb7ee7dfa6a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=720&q=80"
onClick={() => setVisible(false)}
/>
{!visible && (
<Overlay blur={15} center>
<Button color="red" radius="xl" onClick={() => setVisible(true)}>
NSFW, click to reveal
</Button>
</Overlay>
)}
</AspectRatio>
);
}

Modal and Drawer components improvements

Compound components

Modal and Drawer components now expose compound components that can be used to build custom modals and drawers. This feature allows you to have full control over the component rendering. Previous approach with single Modal/Drawer component will still work the same way as before.

import { useDisclosure } from '@asuikit/hooks';
import { Modal, Button, Group } from '@asuikit/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal.Root opened={opened} onClose={close}>
<Modal.Overlay />
<Modal.Content>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
<Modal.CloseButton />
</Modal.Header>
<Modal.Body>Modal content</Modal.Body>
</Modal.Content>
</Modal.Root>
<Group position="center">
<Button onClick={open}>Open modal</Button>
</Group>
</>
);
}

Built in ScrollArea

Modal and Drawer components now use ScrollArea component to handle scroll:

import { useDisclosure } from '@asuikit/hooks';
import { Modal, Group, Button } from '@asuikit/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
const content = Array(100)
.fill(0)
.map((_, index) => <p key={index}>Modal with scroll</p>);
return (
<>
<Modal opened={opened} onClose={close} title="Header is sticky">
{content}
</Modal>
<Group position="center">
<Button onClick={open}>Open modal</Button>
</Group>
</>
);
}

Modal offset

Modal component now supports xOffset and yOffset props to control vertical and horizontal offsets of the modal content:

import { useDisclosure } from '@asuikit/hooks';
import { Modal, Button, Group } from '@asuikit/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal opened={opened} onClose={close} title="Authentication" yOffset="1vh" xOffset={0}>
{/* Modal content */}
</Modal>
<Group position="center">
<Button onClick={open}>Open modal</Button>
</Group>
</>
);
}

keepMounted prop

Components that use Transition now support keepMounted. When keepMounted prop is set component will not be unmounted from the DOM and instead it will be hidden with display: none styles.

keepMounted prop is supported by the following components:

Pagination component improvements

Pagination component now supports changing icons with props and compound components:

import { Group, Pagination } from '@asuikit/core';
function Demo() {
return (
<Pagination.Root total={10}>
<Group spacing={5} position="center">
<Pagination.First />
<Pagination.Previous />
<Pagination.Items />
<Pagination.Next />
<Pagination.Last />
</Group>
</Pagination.Root>
);
}

@asuikit/spotlight improvements

Controlled actions

You can now fully control actions state:

import { useState } from 'react';
import { Group, Button } from '@asuikit/core';
import { SpotlightProvider, spotlight } from '@asuikit/spotlight';
import { IconAlien, IconSearch } from '@tabler/icons-react';
function SpotlightControls() {
const [registered, setRegistered] = useState(false);
return (
<Group position="center">
<Button onClick={spotlight.open}>Open spotlight</Button>
{registered ? (
<Button
variant="outline"
color="red"
onClick={() => {
setRegistered(false);
spotlight.removeActions(['secret-action-1', 'secret-action-2']);
}}
>
Remove extra actions
</Button>
) : (
<Button
variant="outline"
onClick={() => {
setRegistered(true);
spotlight.registerActions([
{
id: 'secret-action-1',
title: 'Secret action',
description: 'It was registered with a button click',
icon: <IconAlien size="1.2rem" />,
onTrigger: () => console.log('Secret'),
},
{
id: 'secret-action-2',
title: 'Another secret action',
description: 'You can register multiple actions with just one command',
icon: <IconAlien size="1.2rem" />,
onTrigger: () => console.log('Secret'),
},
]);
}}
>
Register extra actions
</Button>
)}
</Group>
);
}
export function Demo() {
// It is required to store actions in state for register/remove functions to work
const [actions, setActions] = useState([/* ... see in previous demos */]);
return (
<SpotlightProvider
actions={actions}
onActionsChange={setActions}
searchIcon={<IconSearch size="1.2rem" />}
searchPlaceholder="Search..."
shortcut="mod + shift + C"
>
<SpotlightControls />
</SpotlightProvider>
);
}

Controlled search query

You can now fully control search query:

import { useState } from 'react';
import { Button, Group } from '@asuikit/core';
import { SpotlightProvider, spotlight, SpotlightAction } from '@asuikit/spotlight';
function SpotlightControl() {
return (
<Group position="center">
<Button onClick={spotlight.open}>Open spotlight</Button>
</Group>
);
}
function Demo() {
const [query, setQuery] = useState('');
const actions: SpotlightAction[] =
query !== '%%secret%%'
? [
{
title: 'Reveal secret actions',
description: 'Click this action to reveal secret actions',
onTrigger: () => setQuery('%%secret%%'),
closeOnTrigger: false,
},
]
: [
{ title: 'Super secret action', keywords: '%%secret%%', onTrigger: () => {} },
{
title: 'Rick roll',
description: 'Do not click',
keywords: '%%secret%%',
onTrigger: () => {
window.location.href = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
},
},
];
return (
<SpotlightProvider
actions={actions}
query={query}
onQueryChange={setQuery}
searchIcon={<IconSearch size="1.2rem" />}
searchPlaceholder="Search..."
shortcut="mod + shift + 1"
nothingFoundMessage="Nothing found..."
>
<SpotlightControl />
</SpotlightProvider>
);
}

Other changes

  • rightSection of all inputs is now based on size prop by default (previously it was a static value)
  • Chip component now supports filled, outline and light variants
  • theme.headings.fontFamily now fallbacks to theme.fontFamily if value is not defined on MantineProvider
  • @asuikit/notifications package now exports notifications object that includes functions to show, update, hide, clean and clean queue
  • @asuikit/nprogress, @asuikit/modals and @asuikit/spotlight packages now exports nprogress, modals and spotlight objects with all package methods
  • use-os hook now sets initial value in useLayoutEffect by default (configurable with option) to avoid hydration mismatches
  • use-id hook now always generate random id when component is mounted to replace id generated by React.useId hook. This change prevents browser from showing incorrect autocomplete suggestions for inputs.
  • Timeline component now supports root Styles API selector
  • SegmentedControl component now supports readOnly prop
  • Kbd component now supports size prop
  • use-form now supports form.getTransformedValues handler
  • Tooltip now has better color contrast with dark color scheme
  • Highlight component now supports changing styles per highlighted substring
  • JsonInput component now supports serialize and deserialize props to allow custom JSON formats
  • Modals manager now supports type safe context modals
  • @asuikit/form now exports new matchesField validator
  • form.getInputProps withError parameter is now true by default for all inputs
  • New use-headroom hook

Previous documentation versions