Patterns
Standard Month Grid
When to use:
- users pick a month, such as a billing period, a report month, or a card expiry month
Composition notes:
- let
MonthPickerLayoutgenerate the grid; it renders 12 or 13 months, depending on the calendar system - pass
localeto the root once; the layout reads it for the month names - remember that cells are keyed by the first day of each month
Trade-offs:
- simple and reliable
- one year at a time; the app adds year navigation (see Controlled/Stateful)
import { MonthPicker, MonthPickerCell, MonthPickerLayout } from '@vega-ui/react';
export default function MonthsOfOneYear() {
return (
<MonthPicker aria-label='Start month, 2026' locale='en-US' year='2026-01-01' defaultSelected='2026-03-01' style={{ width: '100%' }}>
<MonthPickerLayout>
<MonthPickerCell />
</MonthPickerLayout>
</MonthPicker>
);
}Dense Embedded Month Selector
When to use:
- the month selector is part of a toolbar, a filter popover, or a side panel
Composition notes:
- use four columns and
format='short'so the year fits in three rows - keep the root
sizesmall, and put the year control next to the grid - the example keeps the full month and year in the trigger and in its accessible name
Trade-offs:
- compact
- short names are ambiguous in some locales; keep the full name in the trigger or summary
import {
Button,
Icon,
MonthPicker,
MonthPickerCell,
MonthPickerLayout,
Popover,
PopoverContent,
PopoverTrigger,
} from '@vega-ui/react';
import { ChevronDown } from '@vega-ui/icons';
import { useState } from 'react';Custom Grid Rendering
When to use:
- the row structure itself must change, which a cell template cannot do
Composition notes:
- build rows with
createMonthPickerGridinstead of ordering months by hand; pass the samecalendaras the picker - format labels with
formatCalendarDatein that calendar (orIntl.DateTimeFormatfor Gregorian keys), never from the ISO key - when the label is shortened, as with narrow names here, give the full name in
aria-label
Trade-offs:
- full control over markup
- labels and locale are the app's job; prefer a cell template when only the content changes
import {
MonthPicker,
MonthPickerItem,
MonthPickerRow,
MonthPickerRowGroup,
createMonthPickerGrid,
} from '@vega-ui/react';
const YEAR = '2026-01-01';
const narrowFormat = new Intl.DateTimeFormat('en-US', { month: 'narrow', timeZone: 'UTC' });
const longFormat = new Intl.DateTimeFormat('en-US', { month: 'long', timeZone: 'UTC' });
const rows = createMonthPickerGrid({ year: YEAR, cols: 6 });Cell Template
When to use:
- month cells need extra content such as a total, a status, or a hint
Composition notes:
- children of
MonthPickerLayoutare rendered once per month inside a cell context - read the month with
useMonthPickerCellContext():{ col, date, fields, label };dateis the first day of the month - render the content inside
MonthPickerCellso the cell keeps selection, focus, and disabled states - take month numbers from
labelorfields, never from the ISOdatestring; they differ in non-Gregorian calendars - look data up by
date, which is the same in every calendar system
Trade-offs:
- keeps the grid, keys, and keyboard behavior of the layout
- richer cells can crowd small sizes
import {
MonthPicker,
MonthPickerCell,
MonthPickerLayout,
useMonthPickerCellContext,
} from '@vega-ui/react';
const spending: Record<string, number> = {
'2026-01-01': 1240,
'2026-02-01': 980,
'2026-03-01': 1415,
'2026-04-01': 1102,Comparison
Quick Decision Rule
Use MonthPicker when users should choose a month from a grid. Use DayPicker for specific dates and YearPicker for year selection.
MonthPicker vs DayPicker
- Use
MonthPickerfor month-level choices. - Use
DayPickerfor day-level selection.
MonthPicker vs YearPicker
- Use
MonthPickerfor the month within a year context. - Use
YearPickerwhen the year itself is the target.
Choose This Component When
- the value is a month
- a dense month grid is the right interaction
Do Not Choose This Component When
- users need a specific date or year instead of a month
Troubleshooting
The Month Labels Feel Inconsistent With The Rest Of The Date UI
Symptom
Month names in the picker do not match other date surfaces.
Likely Cause
Labels were hardcoded or formatted with a different locale strategy.
How To Verify
- compare the picker labels with the rest of the app’s date formatting
Fix
Use locale-driven formatting consistently and prefer the supplied layout/helper functions.
Custom Grid Rendering Breaks Selection Clarity
Symptom
Months can still be selected, but users cannot tell which month is active or selected.
Likely Cause
Custom rendering discarded key selection-state affordances.
How To Verify
- test selected, active, and disabled month states in the custom layout
Fix
Preserve the state cues from the standard month item pattern.
The Picker Feels Like A Generic Grid Instead Of A Calendar Primitive
Symptom
The UI technically works, but it no longer reads as a coherent month selector.
Likely Cause
The layout was customized beyond the point where month semantics stay obvious.
How To Verify
- review the component without developer context
Fix
Keep month labels and ordering explicit, and lean on the provided layout/helper APIs where possible.