QuarterPicker

Inline quarter, multiple quarters and quarters range picker

Usage

QuarterPicker works the same way as MonthPicker, but with quarters instead of months. The value is a date string in YYYY-MM-DD format that points to the first day of the selected quarter, for example 2026-04-01 for Q2 2026. Use getQuarterStart exported from @mantine/dates to get the first day of the quarter for any date:

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<string | null>(null);
  return <QuarterPicker value={value} onChange={setValue} />;
}

Allow deselect

Set allowDeselect to allow users to deselect the currently selected quarter by clicking on it. allowDeselect is disregarded when the type prop is range or multiple. When a quarter is deselected, onChange is called with null.

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<string | null>(null);
  return <QuarterPicker allowDeselect value={value} onChange={setValue} />;
}

Multiple quarters

Set type="multiple" to allow users to pick multiple quarters:

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<string[]>([]);
  return <QuarterPicker type="multiple" value={value} onChange={setValue} />;
}

Quarters range

Set type="range" to allow users to pick a quarters range. The value is a tuple of the first day of the first quarter and the first day of the last quarter:

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<[string | null, string | null]>([null, null]);
  return <QuarterPicker type="range" value={value} onChange={setValue} />;
}

Single quarter in range

By default, it is not allowed to select a single quarter as a range – when the user clicks the same quarter a second time, it is deselected. To change this behavior, set the allowSingleDateInRange prop. allowSingleDateInRange is ignored when the type prop is not range.

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<[string | null, string | null]>([null, null]);
  return (
    <QuarterPicker type="range" allowSingleDateInRange value={value} onChange={setValue} />
  );
}

Presets

Use the presets prop to add custom quarter presets. Presets are displayed next to the calendar. Any date inside the quarter can be used as a preset value.

import dayjs from 'dayjs';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
import { QuarterPicker } from '@mantine/dates';

dayjs.extend(quarterOfYear);

function Demo() {
  return (
    <QuarterPicker
      presets={[
        { value: dayjs().startOf('quarter').format('YYYY-MM-DD'), label: 'This quarter' },
        { value: dayjs().add(1, 'quarter').startOf('quarter').format('YYYY-MM-DD'), label: 'Next quarter' },
        { value: dayjs().subtract(1, 'quarter').startOf('quarter').format('YYYY-MM-DD'), label: 'Last quarter' },
        { value: dayjs().add(1, 'year').startOf('year').format('YYYY-MM-DD'), label: 'Q1 next year' },
      ]}
    />
  );
}

@mantine/dates registers the dayjs quarterOfYear and advancedFormat plugins: you can use dayjs().startOf('quarter') and the Q format token. To use the quarter unit with TypeScript, extend dayjs with the quarterOfYear plugin in your code, as shown in the demo above.

To use presets with type="range", define the value as a tuple of two dates:

import dayjs from 'dayjs';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

dayjs.extend(quarterOfYear);

function Demo() {
  const [value, setValue] = useState<[string | null, string | null]>([null, null]);
  return (
    <QuarterPicker
      type="range"
      value={value}
      onChange={setValue}
      presets={[
        {
          value: [dayjs().startOf('year').format('YYYY-MM-DD'), dayjs().startOf('quarter').format('YYYY-MM-DD')],
          label: 'Year to date',
        },
        {
          value: [dayjs().startOf('year').format('YYYY-MM-DD'), dayjs().startOf('year').add(9, 'month').format('YYYY-MM-DD')],
          label: 'This year',
        },
        {
          value: [dayjs().subtract(1, 'year').startOf('year').format('YYYY-MM-DD'), dayjs().subtract(1, 'year').startOf('year').add(9, 'month').format('YYYY-MM-DD')],
          label: 'Last year',
        },
        {
          value: [dayjs().startOf('quarter').format('YYYY-MM-DD'), dayjs().add(1, 'quarter').startOf('quarter').format('YYYY-MM-DD')],
          label: 'Next two quarters',
        },
      ]}
    />
  );
}

Default date

Use the defaultDate prop to set the date value that will be used to determine which year should be displayed initially. Only the year part of the value is used. Note that if you set the date prop, then the defaultDate value will be ignored.

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

function Demo() {
  return <QuarterPicker defaultDate="2015-01-01" />;
}

Min and max date

Set the minDate and maxDate props to define minimum and maximum dates. Quarters that end before minDate or start after maxDate are disabled. If the previous/next year is not available, then the corresponding control will be disabled.

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<string | null>(null);
  return (
    <QuarterPicker
      value={value}
      onChange={setValue}
      defaultDate="2026-01-01"
      minDate="2026-04-01"
      maxDate="2027-07-01"
    />
  );
}

Add props to year and quarter control

You can add props to year and quarter controls with the getYearControlProps and getQuarterControlProps functions. Both functions accept a date as a single argument, and props returned from the function will be added to the year/quarter control. For example, it can be used to disable a specific control or add styles:

import dayjs from 'dayjs';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  return (
    <QuarterPicker
      getYearControlProps={(date) => {
        if (dayjs(date).year() === new Date().getFullYear()) {
          return { style: { color: 'var(--mantine-color-blue-filled)', fontWeight: 700 } };
        }
        if (dayjs(date).year() === new Date().getFullYear() + 1) {
          return { disabled: true };
        }
        return {};
      }}
      getQuarterControlProps={(date) => {
        if (dayjs(date).month() === 3) {
          return { style: { color: 'var(--mantine-color-blue-filled)', fontWeight: 700 } };
        }
        if (dayjs(date).month() === 9) {
          return { disabled: true };
        }
        return {};
      }}
    />
  );
}

Number of columns

Set the numberOfColumns prop to define the number of pickers that will be rendered side by side:

Demo is not available on small screens. Make your screen larger to see the demo.

import { useState } from 'react';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  const [value, setValue] = useState<[string | null, string | null]>([null, null]);
  return (
    <QuarterPicker type="range" numberOfColumns={2} value={value} onChange={setValue} />
  );
}

Max level

To disallow users from going to the decade level, set maxLevel="year":

2026
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  return <QuarterPicker maxLevel="year" />;
}

Full width

Set the fullWidth prop to make the quarter picker stretch to fill 100% of its parent container width:

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

function Demo() {
  return <QuarterPicker fullWidth />;
}

Size

Size
import dayjs from 'dayjs';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  return <QuarterPicker defaultValue={dayjs().format('YYYY-MM-DD')} />;
}

Change year and quarter controls format

Use the yearsListFormat and quartersListFormat props to change the dayjs format of year/quarter controls:

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

function Demo() {
  return <QuarterPicker quartersListFormat="[Quarter] Q" yearsListFormat="YY" />;
}

Change label format

Use decadeLabelFormat and yearLabelFormat to change the dayjs format of the decade/year label:

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

function Demo() {
  return <QuarterPicker yearLabelFormat="YYYY [year]" decadeLabelFormat="YY" />;
}

Localization

Usually it is better to specify the @mantine/dates package locale in DatesProvider, but you can also override the locale per component:

import 'dayjs/locale/ru';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  return <QuarterPicker locale="ru" />;
}

Native level select

Set the withNativeLevelSelect prop to replace the calendar header level button with a native <select> element:

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

function Demo() {
  return <QuarterPicker withNativeLevelSelect />;
}

Accessibility

Aria labels

Set the ariaLabels prop to specify aria-label attributes for next/previous controls:

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

function Demo() {
  return (
    <QuarterPicker
      ariaLabels={{
        nextDecade: 'Next decade',
        previousDecade: 'Previous decade',
        nextYear: 'Next year',
        previousYear: 'Previous year',
        yearLevelControl: 'Change to decade view',
      }}
    />
  );
}

Year/quarter control aria-label

Use getYearControlProps/getQuarterControlProps to customize the aria-label attribute:

import dayjs from 'dayjs';
import { QuarterPicker } from '@mantine/dates';

function Demo() {
  return (
    <QuarterPicker
      getYearControlProps={(date) => ({
        'aria-label': `Select year ${dayjs(date).year()}`,
      })}
      getQuarterControlProps={(date) => ({
        'aria-label': `Select ${dayjs(date).format('[Q]Q YYYY')}`,
      })}
    />
  );
}

Keyboard interactions

Note that the following events will only trigger if focus is on a quarter control. When arrow navigation reaches the edge of the grid, the calendar switches to the previous/next year and focuses the corresponding quarter.

KeyDescription
ArrowRightFocuses next non-disabled quarter, switches to the next year if needed
ArrowLeftFocuses previous non-disabled quarter, switches to the previous year if needed
ArrowDownFocuses the same quarter of the next year
ArrowUpFocuses the same quarter of the previous year

When presets are used, only one preset button is in the tab order. With focus on a preset, ArrowDown and ArrowUp move focus between presets without selecting them, Enter or Space selects the focused preset, and Tab moves focus to the calendar.

When the level is changed with the keyboard (for example, Enter on the year label), focus moves to the label of the new level or to the grid control in the tab order if the new level does not have a clickable label.