Month day picker
Picks a month and day for a date that repeats every year.
Try it
Start on 31 January, jump to April, then back. Compare the two overflow rules.
Stored day 31 · shows January 31
Jump to
Overflow
Year
Size
Error
Disabled
<WMonthDayPicker
value={repeatsOn}
onChange={setRepeatsOn}
year={2026}
overflow="clamp"
size="sm"
ariaLabel="Repeats on"
/>When to use
- Use it for a date that repeats every year, where the stored value carries no year.
- Use
holdwhen the chosen day must survive a change of month, such as the 31st. - Use
clampwhen the date must always exist in the month shown.
Don’t use it
- For one date in one year. Use Date picker.
- For a span of dates. Use Date range selector.
- When a time matters too. Use Date time picker.
Overflow
When a month is shorter than the chosen day, clamp moves the day to the month’s last day. hold keeps the stored day, shows the last day, and notes the held day beside the field.
clamp
hold
<WMonthDayPicker value={repeatsOn} onChange={setRepeatsOn} overflow="clamp" />
<WMonthDayPicker value={repeatsOn} onChange={setRepeatsOn} overflow="hold" />2026
2028
year. The 29th shows only in a leap year.Sizes and states
Two heights, 36 and 44px, to match the other fields. Error and disabled always apply to both selects.
Repeats on
Every year, on this date.
lg · 44
error
disabled
<WFormRow label="Repeats on" help="Every year, on this date.">
<WMonthDayPicker value={repeatsOn} onChange={setRepeatsOn} width="100%" ariaLabel="Repeats on" />
</WFormRow>Accessibility
The selects are announced as Month and Day. Pass ariaLabel to name the pair, usually with the form row’s label. A held day is announced as it appears.
| Key | What it does |
|---|---|
| Tab | Moves focus to the month, then the day, closing any open list. |
| ↓ / ↑ | Opens the list, then moves through it. |
| Enter / Space | Opens or closes the list, or chooses the highlighted option. |
| Escape | Closes the list and keeps focus on the select. |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | MonthDay | — | The stored { month, day }. Month runs 1 to 12. |
| defaultValue | MonthDay | January 31 | Starting value when value isn’t set. |
| onChange | (value) => void | — | Called with the new month and day. |
| year | number | current year | Sets February’s length. |
| overflow | 'clamp' | 'hold' | 'clamp' | What a too-short month does to the day. |
| size | 'sm' | 'lg' | 'sm' | 36 or 44px. |
| width | number | string | 268 | Total width. The day select stays 88px, 96px at lg. |
| disabled | boolean | false | Disables both selects. |
| error | boolean | false | Error border on both selects. |
| ariaLabel | string | — | Accessible name for the pair. |
Tokens
| Token | Value | Where it lands |
|---|---|---|
| --radius-lg | 8px | Both frames, and the open list. |
| --global-neutral-grey-600 | #DCDCDE | Border at rest. |
| --global-neutral-grey-800 | #ADACB0 | Border on hover, disabled chevron. |
| --global-blue-1000 | #1877F2 | Focus edge, halo and keyboard row. |
| --global-red-800 | #E12121 | Error edge. |
| --global-neutral-grey-300 | #F1F1F1 | Hovered and chosen rows, disabled ground. |
| --global-neutral-grey-500 | #E6E6E6 | Open list border, disabled border. |
| --global-neutral-grey-1100 | #2D2B32 | Chosen month and day, hovered or open chevron. |
| --global-neutral-grey-900 | #7F7D83 | Chevron at rest, disabled value. |
| --global-neutral-grey-1200 | #1D1C20 | Option text. |
| --global-blue-1100 | #0C296A | The chosen option’s text. |
| --global-neutral-grey-1000 | #4F4D55 | Placeholders and the held-day note. |
| --shadow-dropdown | 0 4px 12px rgba(0,0,0,.08), … | The open list. |
| --spacing-2 | 8px | Gap between month and day. |