MonthPicker

A field that opens a year of months to choose a month.

BetaSince 1.0.0
On this page

Import

import { MonthPicker } from '@envsemble/envui';

Usage

A MonthPicker takes its label, a description and an error, and its value is a month as YYYY-MM.

  • Uncontrolled: defaultValue, which a form reset restores.
  • Controlled: value and onValueChange, which receives the month, or null once the field is cleared.
  • clearable adds a clear button to the field and the popup.
ReportMonth.tsx
import { useState } from 'react';
import { MonthPicker } from '@envsemble/envui';

export default function ReportMonth() {
  const [month, setMonth] = useState<string | null>('2026-10');
  return (
    <div style={{ inlineSize: 'min(100%, 16rem)' }}>
      <MonthPicker
        label="Report month"
        description="The month the report covers."
        value={month}
        onValueChange={setMonth}
        clearable
      />
    </div>
  );
}

Range and format

min and max, as YYYY-MM, make earlier and later months unavailable, as the FiscalYear example shows. formatOptions takes Intl.DateTimeFormat options for the shown value, by default the long month and the year, as the ShortFormat example shows; locale is EnvUIProvider's, else the browser's, and months are Gregorian, also in a locale with a calendar of its own.

<MonthPicker label="Budget month" min="2026-04" max="2027-03" />
<MonthPicker label="Expires" formatOptions={{ month: '2-digit', year: '2-digit' }} />

In a form

name submits the month as YYYY-MM, and required keeps an empty field's form from submitting. Use readOnly, not disabled, for a month people can't change.

<form onSubmit={submit}>
  <MonthPicker label="Period" name="period" placeholder="Choose a month" required />
  <Button type="submit">Submit expenses</Button>
</form>

Sizes and the popup

size is sm, md or lg; without it the field takes its container's control height. visibleLabel={false} hides the label for a field whose purpose is clear, and placeholder shows while it is empty. open, defaultOpen and onOpenChange control the popup; onOpenChange also receives why it opens or closes, PickerOpenChangeDetails. clearLabel, thisMonthLabel, previousYearLabel and nextYearLabel name its buttons.

Composition

The field, env-month-picker, shares DatePicker's parts: the control, env-date-picker-control, with the label, env-date-picker-label, the value, env-date-picker-value, the clear button, env-date-picker-clear, and the calendar icon, env-date-picker-icon; then the description, env-field-description, and the error, env-field-error. The popup is DatePicker's picker card, env-picker-popup with env-date-picker-popup and env-month-picker-popup. Its body, env-picker-popup-body, has a header, env-month-picker-header, with the previous year, env-month-picker-previous, the year, env-month-picker-title, and the next year, env-month-picker-next; the year's grid, env-month-picker-year and env-month-picker-grid, of months, env-month-picker-month, each with data-month and a mark, env-month-picker-month-mark; and its footer, env-picker-popup-footer with env-date-picker-actions, the actions. ref reaches the field's button, and className and style its root.

Customize

Its popup is frosted, as every popup is: --env-popup-opacity, --env-popup-blur and --env-popup-shadow, set on a theme, change it, as Popover describes.

Accessibility

You provide

  • A label, or aria-label on a field without one.
  • Validation and its error.
  • The labels in the application's language.

envUI provides

  • The field as a combobox button named by its label, with its description and error.
  • The year as a grid of months, each named by month and year, with one tab stop.

Props

MonthPicker

A field for a month of a year that shows the value in the reader's locale and opens a year of months to choose it from, with keyboard access like Calendar's.

PropTypeDescription
value
stringnull
The value: a month as YYYY-MM. null, or an empty string, for none.
defaultValueDefault null
stringnull
The value an uncontrolled field starts with, and that a form reset restores; none by default.
onValueChange
(value: string | null) => void
Receives the new value as YYYY-MM, or null once the field is cleared.
min
string
The earliest month, as YYYY-MM; earlier months are unavailable.
max
string
The latest month, as YYYY-MM; later months are unavailable.
locale
string
The locale of the shown value and the month names: EnvUIProvider's, else the browser's. Months are Gregorian, also in a locale with a calendar of its own.
formatOptions
Intl.DateTimeFormatOptions
How the field shows the value: Intl.DateTimeFormat options, by default the long month and the year, in the Gregorian calendar unless they name another.
clearLabelDefault 'Clear', or EnvUIProvider's messages.monthPicker.clear
string
Accessible name of the field's clear button and text of the popup's.
thisMonthLabelDefault 'This month', or EnvUIProvider's messages.monthPicker.thisMonth
string
The popup's shortcut to the current month.
previousYearLabelDefault 'Previous year', or EnvUIProvider's messages.monthPicker.previousYear
string
Accessible name of the popup's previous year button.
nextYearLabelDefault 'Next year', or EnvUIProvider's messages.monthPicker.nextYear
string
Accessible name of the popup's next year button.
ref
Ref<HTMLButtonElement>
The field's button, which shows the value and opens the popup.
className
string
The field's class, on its root element.
style
CSSProperties
Styles of the field's root element.
name
string
The name the value is submitted under with a form.
requiredDefault false
boolean
A value is needed: an empty field keeps its form from submitting and takes focus.
readOnlyDefault false
boolean
The value can be read and focused but not changed.
placeholder
string
Shown while the field is empty and its label floats or is hidden.
clearableDefault false
boolean
A clear button in the field and in the popup removes the value.
open
boolean
Whether the popup is open; with `onOpenChange` it controls it.
defaultOpenDefault false
boolean
Whether an uncontrolled popup starts open; closed by default.
onOpenChange
(open: boolean, details: PickerOpenChangeDetails) => void
Called with the new state, and why, when the popup opens or closes.
label
ReactNode
The field's visible name, such as Project name; it also names the control for assistive technology.
description
ReactNode
Lasting guidance under the field, such as a format or a limit, linked to the control as its description.
error
ReactNode
A message under the field that says how to correct the value. While it is set, the control is invalid (aria-invalid) and the message joins its description, after the description.
size
'sm''md''lg'
The control height, sm, md or lg; without it, the container's, and else md. sm is for a field with its label hidden.
visibleLabelDefault true
boolean
The label shows in the field, where it rests while the field is empty and floats into the outline while the field is in use or has a value. false hides it, for a field whose purpose is clear without it, such as a search in a toolbar: the label still names the field for assistive technology, and a placeholder gives the visible guidance.

Also accepts the native props of <button>, such as ref, className and aria-* attributes.

Part names

Each part's class and state attributes are public and versioned, for an application's CSS to style.

env-month-picker
The month field.
env-month-picker-grid
The grid of months.
env-month-picker-header
The row with the year and the previous and next buttons.
env-month-picker-month
One month.
env-month-picker-month-mark
The mark under a month, such as the current one.
env-month-picker-next
The button for the next year.
env-month-picker-popup
The popup with the months.
env-month-picker-previous
The button for the previous year.
env-month-picker-title
The year.
env-month-picker-year
The year's grid of months.
data-month
Any value, or present on env-month-picker-month

Strings

EnvUIProvider's messages overrides each, and a component's own label prop wins over it.

messages.monthPicker.clear
"Clear" The clear button's name.
messages.monthPicker.thisMonth
"This month" Picks the current month.
messages.monthPicker.previousYear
"Previous year" The previous-year button's name.
messages.monthPicker.nextYear
"Next year" The next-year button's name.

Changelog

1.0.0

showLabel is visibleLabel, named after the label that visibleLabel={false} hides.

MonthPicker, for a month of a year, with min and max.

1.0.0-prerelease.6

Colors under the pointer and while pressed change with --env-motion-ease-enter, rather than easing in slowly, so hover and press show from the first frame.

The popup opens over --env-motion-duration-medium, fading in and growing from 98 % with --env-motion-ease-enter, rather than growing from 96 % over the slow duration, so it shows from its first frames rather than late.

The year buttons show larger arrows, 1.25 rem, on slightly smaller buttons, and the header keeps a little room under it, as the calendar's.

The grid's month names keep one length where the locale makes nearly all of them that long, such as Sep rather than Sept among en-GB's three-letter months; names with punctuation, and locales whose names vary, keep the locale's own.

Months outside min and max take the disabled text color, faded, as a calendar's unavailable days do; this month keeps its accent color.

The floating variant and the variant prop are gone: the field is outlined, and takes size="lg" in a long form on a page. The field takes a text area's rounded corners rather than round ends. A small one with a visible label takes the medium height, so its floated label and its value each have room, and says so in the console while developing: sm is for a field with its label hidden.

1.0.0-prerelease.5

The popup is frosted: the popup's color lets a little of what is behind through, blurred, with a soft shadow and no outline edge but a faint hairline in dark, and is solid with its edge at high contrast and with reduced transparency. Its inset is a panel's, as wide as a popup row's corner: 14 px, 11.2 px at the compact scale. The year leads its header, its buttons side by side at the end; this month is in the accent color rather than ringed, and a month under the pointer takes the neutral fill.