Month Picker
import { MonthPicker } from '@absoluteui/components/month-picker';import '@absoluteui/components/month-picker/style.css';Using Angular? See Month Picker for Angular.
What it does
Section titled “What it does”Entry of a calendar month without a day. MonthPicker renders locale-ordered month and year segments inside a labelled group, plus a “Choose month” button that opens a non-modal dialog popup with a grid of the twelve months of a year (paged by year). The value is a PlainYearMonth ({ kind: 'PlainYearMonth', year, month }, created with plainYearMonth(year, month)); it has no day and no timezone. Validation is localized and a hidden input submits ISO 8601 YYYY-MM. Month, Year, and Quarter Picker share one engine and behave the same apart from the period.
When to use
Section titled “When to use”- A month without a day: billing or reporting periods, card expiry, a month of employment, a monthly budget.
- Users should be able to type a month quickly and also look it up in a grid of months.
- Month fields with bounds or unavailable months (for example months already closed).
When not to use
Section titled “When not to use”- A specific day: use Date Picker or Date Input.
- A whole year: use Year Picker. A calendar quarter: use Quarter Picker.
- A range of months: use two Month Pickers and a cross-field rule.
- A handful of fixed months that should stay visible: use Radio Group or Select.
Examples
Section titled “Examples”Required month with bounds
Section titled “Required month with bounds”import { plainYearMonth } from '@absoluteui/core';import { MonthPicker } from '@absoluteui/components/month-picker';
const host = document.createElement('div');document.body.append(host);const picker = MonthPicker.create(host, { label: 'Billing month', name: 'billingMonth', required: true, min: plainYearMonth(2024, 1), max: plainYearMonth(2026, 12),});host.addEventListener('aui-change', () => { host.dataset.valid = String(picker.validity.valid);});Unavailable months, custom validation, and the change detail
Section titled “Unavailable months, custom validation, and the change detail”import { plainYearMonthToString } from '@absoluteui/core';import { MonthPicker, type MonthPickerChangeDetail } from '@absoluteui/components/month-picker';
const host = document.createElement('div');document.body.append(host);MonthPicker.create(host, { label: 'Report month', isMonthDisabled: (value) => value.month === 12, validate: (value) => (value !== null && value.year < 2020 ? 'Reports start in 2020.' : null), closeOnSelect: false,});host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<MonthPickerChangeDetail>).detail; host.dataset.month = value ? plainYearMonthToString(value) : '';});Global timezone and month picker defaults
Section titled “Global timezone and month picker defaults”import { configureAbsoluteUI } from '@absoluteui/core';import '@absoluteui/components/month-picker';
configureAbsoluteUI({ common: { timezone: 'Europe/Berlin' }, components: { monthPicker: { closeOnSelect: false, validationTiming: 'submit' } } });import { plainYearMonthToString } from '@absoluteui/core';import { MonthPicker, type MonthPickerChangeDetail } from '@absoluteui/components/month-picker';import '@absoluteui/components/month-picker/style.css';
const host = document.querySelector<HTMLElement>('#expiry');if (host) { MonthPicker.create(host, { label: 'Card expiry', name: 'expiry', required: true }); host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<MonthPickerChangeDetail>).detail; host.dataset.month = value ? plainYearMonthToString(value) : ''; });}More usage
Section titled “More usage”import { plainYearMonth } from '@absoluteui/core';import { MonthPicker } from '@absoluteui/components/month-picker';
const host = document.createElement('div');document.body.append(host);MonthPicker.create(host, { label: 'Billing month', name: 'billingMonth', required: true, min: plainYearMonth(2024, 1), max: plainYearMonth(2026, 12) });Anatomy
Section titled “Anatomy”<div class="aui-field aui-period-picker aui-month-picker" data-aui-control> (consumer host; registered with Form) <label class="aui-field__label">Label<span class="aui-field__required" aria-hidden="true">*</span></label> <div class="aui-month-picker__group aui-period-picker__group" role="group" aria-labelledby=label aria-describedby> <div class="aui-period-picker__fields"> (LTR-isolated run) <input class="aui-period-picker__segment aui-period-picker__segment--month" aria-label="Month" placeholder="mm"> <span class="aui-period-picker__separator" aria-hidden="true">/</span> <input class="aui-period-picker__segment aui-period-picker__segment--year" aria-label="Year" placeholder="yyyy"> </div> <button class="aui-period-picker__button" aria-haspopup="dialog" aria-expanded aria-controls=popup aria-label="Choose month"> </div> <div class="aui-field__description"> (hidden when empty) <div class="aui-field__error aui-validation-message"> (hidden when no message is shown) <input type="hidden" name> <div class="aui-period-picker__popup" role="dialog" aria-modal="false" aria-label="Choose month" popover="manual"> <div class="aui-period-picker__header"> <button class="aui-period-picker__nav aui-period-picker__prev" aria-label="Previous year"> <div class="aui-period-picker__heading" aria-live="polite">2026</div> <button class="aui-period-picker__nav aui-period-picker__next" aria-label="Next year"> </div> <div class="aui-period-picker__grid aui-month-picker__grid" role="grid" aria-labelledby=heading> <div class="aui-period-picker__row" role="row"> (4 rows of 3) <div class="aui-period-picker__cell" role="gridcell" aria-label="January 2026" tabindex="-1"> <span class="aui-period-picker__cell-text">Jan</span> </div> ... </div> ... </div> </div></div>The popup sits inside the host in the DOM (it renders in the top layer), so moving focus between the segments, the button, and the popup does not mark the field touched, and a picker inside a modal Dialog stays inside the dialog’s subtree.
API reference
Section titled “API reference”Factory
Section titled “Factory”MonthPicker.create(host: HTMLElement, options: MonthPickerOptions): MonthPickerGlobal configuration key: monthPicker (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Visible label and accessible name of the group (via aria-labelledby). Must be a non-empty string. Required. | |
hideLabel |
boolean |
false |
Visually hide the label; it remains the accessible name. |
value |
PlainYearMonth | null |
null |
Value (years 1-9999). The value passed to create() is the value restored by reset(). |
min |
PlainYearMonth | null |
null |
Inclusive lower bound (validation and popup). Must not be after max. |
max |
PlainYearMonth | null |
null |
Inclusive upper bound (validation and popup). |
name |
string |
Form field name; a hidden input carries the ISO 8601 month (YYYY-MM). | |
description |
string |
Help text (text only) referenced by the group’s aria-describedby. | |
required |
boolean |
false |
An empty entry is invalid (value-missing); segments are required and the required indicator is shown. |
disabled |
boolean |
false |
Disables the segments and the button; the popup does not open and the value is not submitted. |
readOnly |
boolean |
false |
Focusable and submitted, but not editable; the popup does not open. |
validate |
(value: PlainYearMonth | null) => string | null |
Consumer validation after the built-in checks; return a non-empty message to mark the value invalid (error ‘custom’). | |
isMonthDisabled |
(value: PlainYearMonth) => boolean |
Return true to disable a month: focusable in the popup but not selectable; typed, it is invalid (error ‘unavailable’). | |
today |
PlainDate |
Advanced: fixed today instead of the current date in timezone; it decides the current month. For tests, server rendering, and demos with a fixed clock. | |
icons |
Partial<MonthPickerIcons> |
Icon slot overrides: calendar, previous, next, error. | |
validationTiming |
'blur' | 'input' | 'submit' |
"blur" |
When validation messages first appear; afterwards they update live. Globally configurable. |
closeOnSelect |
boolean |
true |
Close the popup after a month is picked. Globally configurable. |
locale |
string |
"en-US" |
Segment order and separators, month names, headings, labels, and messages. A change rebuilds the segments and keeps the entry. Globally configurable. Inherited from common configuration. |
timezone |
string (IANA) |
"UTC" |
Zone used only to determine the current month (aria-current and default focus). Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Popup and grid direction: grid arrow-key mirroring, chevrons, and popup alignment (applied when the popup opens). Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. Registered with Form. |
group |
HTMLDivElement |
The labelled role=group with the segments and the button; control boundary and popup anchor. |
button |
HTMLButtonElement |
Opens the popup (aria-haspopup=dialog). |
popup |
HTMLDivElement |
role=dialog aria-modal=false popup (popover=manual). |
grid |
HTMLDivElement |
The role=grid of months inside the popup. |
value |
PlainYearMonth | null |
Current value; null when empty, incomplete, or failing a built-in check. |
validity |
MonthPickerValidity |
{ valid, error, message }; recomputed on every change. |
isOpen |
boolean |
Whether the popup is open. |
name |
string | null |
Form field name. |
label |
string |
Label text. |
disabled |
boolean |
Disabled state. |
dirty |
boolean |
Value differs from the initial value, or the segments hold an entry that does not parse to a value. |
touched |
boolean |
Focus has left the whole control (segments, button, and popup) at least once. |
options |
Readonly<MonthPickerOptions> |
Current instance options. |
focusedValue |
PlainYearMonth |
The month holding the roving tab stop in the popup grid. |
current |
PlainYearMonth |
The month containing today in the configured timezone (or the today option). |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setValue(value: PlainYearMonth | null): void |
Programmatic value (no events); clears an external custom error. Throws MONTH_PICKER_OPTIONS for a non-PlainYearMonth value. |
update(options: Partial<MonthPickerOptions>): void |
Merge, validate, and apply options. Closes an open popup when it becomes disabled or read-only. |
open(): void |
Open the popup and focus the selected month (or the current month), clamped to min/max. No-op when open, disabled, or read-only. |
close(): void |
Close the popup; focus inside it returns to the button. |
reportValidity(): boolean |
Show messages now (for every validation timing) and return validity. |
setCustomError(message: string | null): void |
External error (server, cross-field rule); null or ‘’ clears it; cleared when the user edits. |
getFormValue(): string | null |
ISO 8601 YYYY-MM, or null when the value is null. |
focus(): void |
Focus the first segment. |
reset(): void |
Close, restore the initial value, and clear dirty/touched/submitted state (no events). |
destroy(): void |
Close, remove rendering, host classes, listeners, form registration, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ value: PlainYearMonth | null; validity: MonthPickerValidity } |
Yes | No | The user changed the value or its validity error (typing, stepping, a separator, or picking a month). |
aui-open |
null |
No | No | The popup opened. |
aui-close |
null |
No | No | The popup closed. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-field aui-period-picker aui-month-picker |
Host. |
aui-period-picker--invalid | --disabled | --readonly |
State modifiers on the host. |
aui-field__label | __required | __description | __error |
Shared field chrome (the error is also aui-validation-message). |
aui-month-picker__group aui-period-picker__group |
Labelled group; control boundary, focus indicator, and popup anchor. |
aui-period-picker__fields |
LTR-isolated run of segments and separators. |
aui-period-picker__segment | __segment--month | __segment--year |
Segment inputs. |
aui-period-picker__separator |
Locale separator text (aria-hidden). |
aui-period-picker__button |
Choose month button. |
aui-period-picker__popup |
Top-layer dialog popup. |
aui-period-picker__header | __heading | __nav | __prev | __next |
Popup header: year heading (aria-live) and previous/next year buttons. |
aui-period-picker__grid aui-month-picker__grid |
Grid of 12 months (4 rows of 3). |
aui-period-picker__row |
Grid row. |
aui-period-picker__cell | --selected | --current | --disabled | --empty |
Month cell and its states. |
aui-period-picker__cell-text |
Short month name in a cell. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
calendar |
calendar |
previous |
chevron-left |
next |
chevron-right |
error |
alert-circle |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-hover | --aui-color-on-primary | --aui-color-primary | --aui-color-selected | --aui-color-selected-text | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-height-sm | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-bold | --aui-font-weight-medium | --aui-font-weight-semibold | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3
TypeScript definitions
Section titled “TypeScript definitions”interface PlainYearMonth { readonly kind: 'PlainYearMonth'; readonly year: number; readonly month: number }interface MonthPickerConfig { validationTiming: ValidationTiming; closeOnSelect: boolean }type ValidationTiming = 'blur' | 'input' | 'submit';type MonthPickerError = 'incomplete' | 'invalid' | 'value-missing' | 'range-underflow' | 'range-overflow' | 'unavailable' | 'custom';interface MonthPickerValidity { readonly valid: boolean; readonly error: MonthPickerError | null; readonly message: string }interface MonthPickerChangeDetail { value: PlainYearMonth | null; validity: MonthPickerValidity }interface MonthPickerIcons { calendar: IconRef; previous: IconRef; next: IconRef; error: IconRef }Accessibility
Section titled “Accessibility”Pattern: Segmented month field in a labelled group with a button that opens a non-modal dialog popup (WAI-ARIA APG date picker dialog pattern, non-modal variant) containing a paged role=grid of months with a roving tabindex.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Digits | Month segment | Enters up to two digits; a first digit 2-9 is padded (4 becomes 04) and advances; a first 1 waits for a second digit. Non-digits are removed. |
| Digits | Year segment | Enters up to four digits and advances when full; fewer than four digits is incomplete. |
| / - . , : Space | Segment (not read-only) | Pads a single-digit month and advances to the next segment. |
| ArrowUp / ArrowDown | Segment (not read-only) | Month increments or decrements with wrap (1-12); the year stops at 1 and 9999. An empty month starts at 01 (Up) or 12 (Down); an empty year starts at the current year. |
| ArrowLeft / ArrowRight | Caret at the segment edge, or text selected | Previous or next segment in the visual order of the LTR-isolated segment run (not mirrored in RTL). |
| Backspace | Empty segment | Moves to the previous segment. |
| Alt+ArrowDown | Segment | Opens the popup without changing the segment. |
| Tab / Shift+Tab | Group | Moves through the segments, then the button. |
| Enter / Space | Button | Opens the popup (or closes it when open); focus moves to the selected month, else the current month, clamped to min/max. |
| ArrowRight / ArrowLeft | Month cell | Next / previous month (mirrored in RTL), crossing into the adjacent year. |
| ArrowDown / ArrowUp | Month cell | Same column in the next / previous row (plus or minus 3 months), crossing into the adjacent year. |
| Home / End | Month cell | First / last month of the row. |
| PageDown / PageUp | Month cell | Same month in the next / previous year. |
| Shift+PageDown / Shift+PageUp | Month cell | Same month 10 years later / earlier. |
| Enter / Space | Month cell | Picks the month unless it is disabled; with closeOnSelect (default) the popup closes and focus returns to the button, otherwise focus stays on the cell. Emits aui-change if the value or validity changed. |
| Enter / Space | Previous / next year button | Shows the previous / next year; no-op while aria-disabled. |
| Escape | Popup open | Closes the popup without changing the value; focus inside the popup returns to the button. Only the topmost overlay responds, so a surrounding Dialog stays open. |
| Tab / Shift+Tab | Popup | Moves between the previous and next year buttons and the focused month; focus leaving the popup (other than to the choose button) closes it. |
| Element | Role |
|---|---|
| segment container | group |
| each segment (input type=text, inputmode=numeric) | textbox (native) |
| choose month button | button (native), aria-haspopup=dialog |
| popup | dialog (aria-modal=false) |
| previous / next year buttons | button (native) |
| month grid | grid |
| grid row | row |
| month cell | gridcell |
| separators and icons | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-labelledby |
group | Label id |
aria-describedby |
group | Help text and visible error message ids |
aria-label |
segment | Localized segment name (“Month”, “Year”) |
aria-invalid |
segment | “true” only while an error message is shown |
aria-label |
button | “Choose month”, or “Change month, {value}” (for example “Change month, March 2026”) when a value is set |
aria-haspopup |
button | dialog |
aria-expanded |
button | “true” while the popup is open |
aria-controls |
button | Popup id |
aria-label |
popup | Localized “Choose month” |
aria-modal |
popup | “false” (non-modal; the page stays reachable) |
aria-live |
heading | polite (announces the year when the page changes) |
aria-label |
previous / next buttons | “Previous year” / “Next year” |
aria-disabled |
previous / next buttons | “true” when the page reaches min/max or year 1/9999 (focus stays on the button) |
aria-labelledby |
grid | Heading id |
aria-label |
cell | Long month and year, for example “March 2026” |
aria-selected |
cell | “true” on the selected month only (absent otherwise) |
aria-current |
cell | “date” on the current month (configured timezone or today option) |
aria-disabled |
cell | “true” for months outside min/max or rejected by isMonthDisabled |
Each segment and the button are tab stops. Opening moves focus to one month cell (roving tabindex: exactly one cell has tabindex=0). Movement is clamped to min/max and years 1-9999; disabled months stay focusable. Picking with closeOnSelect, Escape, and closing through the button return focus to the button; focus is moved before the popup hides, so it never falls to the document body. A pointer press outside the popup and the button closes it. Moving focus between the segments, button, and popup does not mark the field touched.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The label is a <label> associated through aria-labelledby because a group is not labelable; clicking the label focuses the first segment.
- The required asterisk is aria-hidden; each segment carries the native required state.
- The segments remain the primary input; the grid is an alternative, and a typed month rejected by isMonthDisabled gets a localized message so both paths agree.
- The popup is non-modal: focus is not trapped and the rest of the page stays reachable.
- Errors appear after focus leaves the whole control by default, so moving between segments does not trigger messages.
- Screen-reader behavior (dialog announcement, page changes, cell states) has not yet been manually verified with NVDA, JAWS, and VoiceOver.
- Segment arrow navigation follows visual order and is not mirrored in RTL, because segments render as an LTR run.
Behavior
Section titled “Behavior”States
Section titled “States”empty, segment focused, partial (incomplete), valid, invalid (message shown), open, cell focused, cell selected, current month, cell disabled, disabled, read-only, required.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| empty | user types part of a month | dirty, incomplete; message shown only with validationTiming: 'input' |
| incomplete | last segment filled | valid, or invalid / range-underflow / range-overflow / unavailable / custom; aui-change |
| closed | button, Alt+ArrowDown, or open() |
open; focus on the selected (else current) month; aui-open |
| open | Enter, Space, or click on an enabled month | value set, aui-change if changed; with closeOnSelect closed, focus on the button, aui-close |
| open | Escape, the button, or close() |
closed; value kept; focus inside the popup returns to the button; aui-close |
| open | Tab out of the popup, or a pointer press outside the popup and button | closed; focus moves on |
| any | focus leaves the host | touched; messages shown (blur timing) |
| any | reportValidity() (for example on form submit) |
submitted; messages shown for every timing |
| invalid (custom error) | user edits | custom error cleared, validity recomputed |
| any | reset() |
initial value; pristine, untouched, closed |
Accessibility notes
Section titled “Accessibility notes”- The segments stay the primary input; the grid is an alternative. A typed month rejected by
isMonthDisabledgets a localized message, so the typed and picked paths agree. - The popup is non-modal: focus is not trapped and the page stays reachable. Escape and outside presses close it through the shared overlay stack, so only the topmost overlay responds.
- Focus is moved before the popup hides, so it never falls to the document body.
- Moving between segments, the button, and the popup does not count as leaving the field; errors appear after the whole control loses focus.
- The label is a
<label>associated througharia-labelledby; clicking it focuses the first segment. The required asterisk isaria-hidden. - Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”The group hugs its segments and button, up to 100% of the container; segments wrap inside the group in very narrow containers. The popup is positioned under the group (bottom-start), is at most the viewport width minus a gutter, caps its height to the available space (--aui-available-height), and scrolls when taller. Cells are at least 4rem wide and one control height tall.
Right-to-left
Section titled “Right-to-left”Segment order and separators come from the locale’s Intl year/month pattern. Segments render as an LTR-isolated run in every direction, so ArrowLeft and ArrowRight in segments follow that visual order and are not mirrored. The button sits at the inline end. The popup and grid take direction: grid ArrowLeft/ArrowRight are mirrored, the chevrons are flipped, and the popup aligns to the inline start of the group.
Theming
Section titled “Theming”Role tokens only. The focused segment uses color-selected / color-selected-text; the selected month uses color-primary / color-on-primary; the current month is bold with an inset color-border-strong border; unavailable months are muted and struck through. In forced-colors mode the focused segment and the selected month use Highlight / HighlightText, the current month gets a CanvasText outline, disabled cells and buttons use GrayText, and the popup has a CanvasText border.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ common: { timezone: 'Europe/Berlin' }, components: { monthPicker: { closeOnSelect: false, validationTiming: 'submit' } } });Changes apply to existing instances immediately; a locale change rebuilds the segments and keeps the entry.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic (update()); there are no init-only options.
Timezones
Section titled “Timezones”Values are PlainYearMonth and never shift. The configured timezone (default UTC, never the host zone) only decides the current month: the cell marked aria-current="date" and the month focused when the popup opens on an empty field. For example, at 2026-09-30 19:00 UTC the current month is September 2026 in UTC but October 2026 with timezone: 'Asia/Kolkata'. The advanced today option pins today to a fixed PlainDate (tests, server rendering, demos).
icons.calendar (default calendar) for the button, icons.previous / icons.next (defaults chevron-left / chevron-right) for the page buttons, and icons.error (default alert-circle) for the validation message.
Security
Section titled “Security”All text uses textContent and Intl formatting; no HTML parsing. Validation messages never include the entered value; range messages include only the formatted bounds. The popup uses the Popover API; no inline handlers. CSP-safe: positioning writes styles through the CSSOM.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. When name is set, a hidden input carries YYYY-MM; it is empty while the entry is empty or fails a built-in check, and disabled (not submitted) while the picker is disabled. A read-only picker is submitted.
Performance
Section titled “Performance”The popup and its 12 cells are created once per picker; opening and paging only re-render cell text and state. Segment keyboard and input handling share one delegated listener each; the grid has one keydown and one click listener. One configuration subscription per instance. Budget: under 5 ms average per MonthPicker.create across 100 instances in headless Chromium.
Supported data scale
Section titled “Supported data scale”100 pickers per page (performance test); years 1 to 9999.
Edge cases
Section titled “Edge cases”- A single
1in the month segment does not advance but already counts as January;13or00reportsinvalid(“Enter a valid month.”). - A month with only one segment filled reports
incomplete(“Enter a complete month.”); a year with fewer than four digits reportsincomplete(“Enter the year with 4 digits.”). - Built-in errors (
incomplete,invalid,range-*,unavailable) setvaluetonull; acustomerror keeps the value (and the hidden input value). - Opening an empty field focuses the current month in the configured zone, clamped to
min/max. - Clicking a month outside
min/maxor rejected byisMonthDisableddoes nothing; Enter on it keeps the popup open. update({ value })changes the value but not the value restored byreset()(thevaluepassed tocreate()).- Inside a modal Dialog, the first Escape closes the popup and the second closes the dialog.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
MONTH_PICKER_OPTIONS |
configuration | Missing or blank label; value/min/max not a PlainYearMonth with year 1-9999; min after max; non-function validate or isMonthDisabled; today not a PlainDate. Details name the property (for example monthPicker.value). |
CFG_INVALID_VALUE |
configuration | Invalid validationTiming, closeOnSelect, locale, timezone, or direction (reported by the configuration engine). |
Validation (validity.error) |
validation | incomplete, invalid, value-missing, range-underflow, range-overflow, unavailable, custom. |
Built-in checks run in that order: empty (value-missing when required), partial (incomplete), four-digit year (incomplete), segment range (invalid), min, max, isMonthDisabled (unavailable), then validate, then an external custom error. English messages: “This field is required.”, “Enter a complete month.”, “Enter the year with 4 digits.”, “Enter a valid month.”, “Enter {min} or later.”, “Enter {max} or earlier.”, “This month is not available.”. A failed construction leaves no rendering, listeners, registrations, or subscriptions behind.
Known limitations
Section titled “Known limitations”- Gregorian calendar only; years 1 to 9999.
- Only ASCII digits are accepted in segments.
- Single months only; ranges need two pickers.
- No Cancel/OK buttons: picking commits.
- Segment arrow navigation is not mirrored in RTL.
- Screen-reader behavior has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML in the label, help text, cells, or messages.
- Non-Gregorian calendars.
- Custom cell content or grid layouts.