Skip to content
v2.5.0
English
Русский
Documentation

YearPicker

YearPicker is the year-selection subsystem of the calendar family.

Patterns

Static Year Grid

When to use:

  • the useful years fit on one page, such as the next few fiscal years or recent model years

Composition notes:

  • use YearPickerLayout; the page starts with the year given by year
  • set rows and cols so the page holds exactly the useful years, and bound them with from and to

Trade-offs:

  • simple and stable
  • no paging; use a scroller for long ranges such as birth years
static-year-grid.tsx · 26 lines
import { Text, YearPicker, YearPickerCell, YearPickerLayout } from '@vega-ui/react';
import { useState } from 'react';

export default function StaticYearGrid() {
  const [year, setYear] = useState<string | null>('2026-01-01');

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-6)', justifyItems: 'start', width: '100%' }}>
      <YearPicker
        aria-label='Budget year'
        locale='en-US'
        year='2025-01-01'

Paged Year Range

When to use:

  • the year range is long, such as birth years, and benefits from snap paging

Composition notes:

  • use YearPickerScroller, YearPickerScrollerContent, and YearPickerScrollerLayout
  • keep period on YearPickerScroller equal to the layout's rows × cols; both default to 12
  • start near the likely answer with year, and bound the range with from and to
  • explain the bounds next to the grid and link the text with aria-describedby

Trade-offs:

  • scales to any range
  • more moving parts than a static grid
paged-year-range.tsx · 38 lines
import {
  HelperText,
  YearPicker,
  YearPickerCell,
  YearPickerScroller,
  YearPickerScrollerContent,
  YearPickerScrollerLayout,
} from '@vega-ui/react';
import { useId, useState } from 'react';

export default function PagedYearRange() {
  const [birthYear, setBirthYear] = useState<string | null>(null);

Custom Grid Rendering

When to use:

  • the row structure itself must change, which a cell template cannot do

Composition notes:

  • build pages with createYearPickerGrid instead of counting years by hand; pass the same calendar as the picker
  • start is the first year of page 0 and offset is the page index
  • format labels with formatCalendarDate in that calendar (or Intl.DateTimeFormat for Gregorian keys), never from the ISO key
  • when the label is shortened, as with two-digit years here, give the full year 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
custom-grid-rendering.tsx · 30 lines
import {
  YearPicker,
  YearPickerItem,
  YearPickerRow,
  YearPickerRowGroup,
  createYearPickerGrid,
} from '@vega-ui/react';

const START = '2020-01-01';
const shortFormat = new Intl.DateTimeFormat('en-US', { year: '2-digit', timeZone: 'UTC' });
const longFormat = new Intl.DateTimeFormat('en-US', { year: 'numeric', timeZone: 'UTC' });
const rows = createYearPickerGrid({ start: START, rows: 2, cols: 5 });

Cell Template

When to use:

  • year cells need extra content such as a count, a status, or a hint

Composition notes:

  • children of YearPickerLayout and YearPickerScrollerLayout are rendered once per year inside a cell context
  • read the year with useYearPickerCellContext(): { col, date, fields, label }; date is the first day of the year
  • render the content inside YearPickerCell so the cell keeps selection, focus, and disabled states
  • take year numbers from label or fields, never from the ISO date string; they differ in non-Gregorian calendars, and an era change gives two cells in one Gregorian year
  • 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
cell-template.tsx · 39 lines
import {
  useYearPickerCellContext,
  YearPicker,
  YearPickerCell,
  YearPickerLayout,
} from '@vega-ui/react';

const reports: Record<string, number> = {
  '2019-01-01': 4,
  '2020-01-01': 12,
  '2021-01-01': 11,
  '2022-01-01': 12,

Comparison

Quick Decision Rule

Use YearPicker when the target value is a year or visible year range. Use MonthPicker or DayPicker when the selection target is more granular.

YearPicker vs MonthPicker

  • Use YearPicker for years.
  • Use MonthPicker for months.

YearPicker vs DayPicker

  • Use YearPicker when year-level selection is the goal.
  • Use DayPicker for actual date selection.

Choose This Component When

  • the product flow needs explicit year picking
  • a paged year range is easier to browse than typing

Do Not Choose This Component When

  • the real target is a month or full date
  • a higher-level calendar mode switch would be simpler

Troubleshooting

The Visible Year Range Does Not Match The Intended Period

Symptom

The grid renders, but the year range shown is not what the product expected.

Likely Cause

Visible year, the layout start / offset, or the scroller period are out of sync.

How To Verify

  • inspect the effective visible year and any current scroller index

Fix

Pass YYYY-MM-DD years, keep period equal to rows × cols, and let YearPickerScrollerLayout derive start and offset.

Large Year Paging Feels Fragile

Symptom

Paging works, but focus or visible context feels unstable across year ranges.

Likely Cause

The scroller integration is not fully synchronized with visible year context.

How To Verify

  • log visible year changes while paging
  • compare them with the rendered range labels

Fix

Keep period equal to the layout's page size and derive range labels from the rendered years.

Custom Layouts Break The Sense Of Calendar Continuity

Symptom

The year grid still renders, but it no longer feels like a coherent picker.

Likely Cause

Too much of the standard grid structure was replaced without preserving year-ordering cues.

How To Verify

  • review the custom layout without developer context

Fix

Preserve explicit year ordering and reuse the helper-generated grids where possible.