---
title: "YearRangePicker"
description: "Presents a calendar view tailored for selecting year ranges."
canonical_url: "https://vinicunca.dev/akar/components/year-range-picker"
---
# YearRangePicker

> Presents a calendar view tailored for selecting year ranges.

## Year Range Picker

`````vue [index.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import { YearRangePickerCell, YearRangePickerCellTrigger, YearRangePickerGrid, YearRangePickerGridBody, YearRangePickerGridRow, YearRangePickerHeader, YearRangePickerHeading, YearRangePickerNext, YearRangePickerPrev, YearRangePickerRoot } from 'akar'
import './styles.css'

const defaultValue = {
  start: new CalendarDate(2020, 1, 1),
  end: new CalendarDate(2024, 1, 1),
}
</script>

<template>
  <div class="akar-demo akar-demo-YearRangePicker">
    <YearRangePickerRoot
        v-slot="{ grid }"
        :default-value="defaultValue"
        class="YearRangePicker"
      >
        <YearRangePickerHeader class="YearRangePickerHeader">
          <YearRangePickerPrev class="YearRangePickerNavButton">
            <PIcon
              name="i-lucide-chevron-left"
              class="Icon"
            />
          </YearRangePickerPrev>
          <YearRangePickerHeading class="YearRangePickerHeading" />
          <YearRangePickerNext class="YearRangePickerNavButton">
            <PIcon
              name="i-lucide-chevron-right"
              class="Icon"
            />
          </YearRangePickerNext>
        </YearRangePickerHeader>
        <div class="YearRangePickerWrapper">
          <YearRangePickerGrid class="YearRangePickerGrid">
            <YearRangePickerGridBody class="YearRangePickerGridWrapper">
              <YearRangePickerGridRow
                v-for="(years, index) in grid.rows"
                :key="`year-${index}`"
                class="YearRangePickerGridRow"
              >
                <YearRangePickerCell
                  v-for="year in years"
                  :key="year.toString()"
                  :date="year"
                  class="YearRangePickerCell"
                >
                  <YearRangePickerCellTrigger
                    :year="year"
                    class="YearRangePickerCellTrigger"
                  />
                </YearRangePickerCell>
              </YearRangePickerGridRow>
            </YearRangePickerGridBody>
          </YearRangePickerGrid>
        </div>
      </YearRangePickerRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-YearRangePicker) {
.Icon {
  width: 1rem;
  height: 1rem;
}

.YearRangePicker {
  margin-top: 1.5rem;
  border-radius: 0.75rem;
  border: 1px solid #e5e5e5;
  background-color: #ffffff;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  padding: 1rem;
}

.YearRangePickerHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.YearRangePickerNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2rem;
  height: 2rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
  border-radius: 0.375rem;
}

.YearRangePickerNavButton:hover {
  background-color: #fafaf9;
}

.YearRangePickerNavButton:focus {
  box-shadow: 0 0 0 2px #000000;
}

.YearRangePickerHeading {
  font-size: 0.875rem;
  font-weight: 500;
  color: #000000;
}

.YearRangePickerWrapper {
  padding-top: 1rem;
}

.YearRangePickerGrid {
  width: 100%;
  user-select: none;
}

.YearRangePickerGridWrapper {
  display: grid;
  gap: 0.25rem 0;
}

.YearRangePickerGridRow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.25rem;
}

.YearRangePickerCell {
  position: relative;
  text-align: center;
}

.YearRangePickerCellTrigger {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  font-weight: 400;
  color: #000000;
  background-color: transparent;
  outline: none;
  cursor: pointer;
  border: none;
}

.YearRangePickerCellTrigger:hover {
  background-color: var(--grass-5);
}

.YearRangePickerCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.YearRangePickerCellTrigger[data-disabled] {
  color: rgba(0, 0, 0, 0.3);
  pointer-events: none;
}

.YearRangePickerCellTrigger[data-selected] {
  background-color: var(--grass-10);
  color: #ffffff;
  font-weight: 500;
}

.YearRangePickerCellTrigger[data-highlighted] {
  background-color: var(--grass-5);
}

.YearRangePickerCellTrigger[data-unavailable] {
  color: rgba(0, 0, 0, 0.3);
  text-decoration: line-through;
  pointer-events: none;
}

.YearRangePickerCellTrigger::before {
  content: '';
  position: absolute;
  top: 0.25rem;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  display: none;
}

.YearRangePickerCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}

.YearRangePickerCellTrigger[data-selected]::before {
  background-color: #ffffff;
}
}
```

## Features

- Full keyboard navigation
- Can be controlled or uncontrolled
- Focus is fully managed
- Localization support
- Highly composable

## Preface

The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript.

We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components.

## Installation

Install the date package.

```bash [pnpm]
pnpm add @internationalized/date
```

```bash [yarn]
yarn add @internationalized/date
```

```bash [npm]
npm install @internationalized/date
```

```bash [bun]
bun add @internationalized/date
```

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import all parts and piece them together.

```vue
<script setup>
import {
  YearRangePickerCell,
  YearRangePickerCellTrigger,
  YearRangePickerGrid,
  YearRangePickerGridBody,
  YearRangePickerGridRow,
  YearRangePickerHeader,
  YearRangePickerHeading,
  YearRangePickerNext,
  YearRangePickerPrev,
  YearRangePickerRoot,
} from 'akar';
</script>

<template>
  <YearRangePickerRoot>
    <YearRangePickerHeader>
      <YearRangePickerPrev />
      <YearRangePickerHeading />
      <YearRangePickerNext />
    </YearRangePickerHeader>
    <YearRangePickerGrid>
      <YearRangePickerGridBody>
        <YearRangePickerGridRow>
          <YearRangePickerCell>
            <YearRangePickerCellTrigger />
          </YearRangePickerCell>
        </YearRangePickerGridRow>
      </YearRangePickerGridBody>
    </YearRangePickerGrid>
  </YearRangePickerRoot>
</template>
```

## API Reference

### Root

Contains all the parts of a year range picker

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `allowNonContiguousRanges` | `false` | `boolean` | When combined with `isYearUnavailable`, determines whether non-contiguous ranges may be selected. |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `calendarLabel` |  | `string` | The accessible label for the calendar |
| `defaultPlaceholder` |  | `DateValue` | The default placeholder date |
| `defaultValue` | `{ start: undefined, end: undefined }` | `DateRange` | The default value for the calendar |
| `dir` |  | `"ltr" \| "rtl"` | The reading direction of the calendar when applicable. |
| `disabled` | `false` | `boolean` | Whether or not the calendar is disabled |
| `fixedDate` |  | `"start" \| "end"` | Which part of the range should be fixed |
| `initialFocus` | `false` | `boolean` | If true, the calendar will focus the selected year on mount |
| `isYearDisabled` |  | `Matcher` | A function that returns whether or not a year is disabled |
| `isYearUnavailable` |  | `Matcher` | A function that returns whether or not a year is unavailable |
| `locale` |  | `string` | The locale to use for formatting dates |
| `maximumYears` |  | `number` | The maximum number of years that can be selected in a range |
| `maxValue` |  | `DateValue` | The maximum date that can be selected |
| `minValue` |  | `DateValue` | The minimum date that can be selected |
| `modelValue` |  | `DateRange \| null` | The controlled selected year range of the year range picker. Can be bound as `v-model`. |
| `nextPage` |  | `((placeholder: DateValue) => DateValue)` | A function that returns the next page of the calendar. |
| `placeholder` |  | `DateValue` | The placeholder date, which is used to determine what year range to display when no date is selected. |
| `preventDeselect` | `false` | `boolean` | Whether or not to prevent the user from deselecting a date without selecting another date first |
| `prevPage` |  | `((placeholder: DateValue) => DateValue)` | A function that returns the previous page of the calendar. |
| `readonly` | `false` | `boolean` | Whether or not the calendar is readonly |
| `yearsPerPage` | `12` | `number` | Number of years to display per page |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `date: DateRange` | Event handler called whenever the model value changes |
| `update:placeholder` | `date: DateValue` | Event handler called whenever the placeholder value changes |
| `update:startValue` | `date: DateValue` | Event handler called whenever the start value changes |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `date` | `DateValue` | The current date of the placeholder |
| `grid` | `Grid<DateValue>` | The grid of years |
| `locale` | `string` | The calendar locale |
| `modelValue` | `DateRange` | The current date range |

[YearRangePickerRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerRoot.vue)

| Data attribute | Value |
| --- | --- |
| `[data-readonly]` | Present when readonly |
| `[data-disabled]` | Present when disabled |
| `[data-invalid]` | Present when invalid |

### Header

Contains the navigation buttons and the heading segments.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[YearRangePickerHeader.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerHeader.vue)

### Prev Button

Calendar navigation button. It navigates the calendar one page (12 years by default) in the past.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `prevPage` |  | `((placeholder: DateValue) => DateValue)` | The function to be used for the prev page. Overwrites the `prevPage` function set on the Root. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `disabled` | `boolean` | Current disable state |

[YearRangePickerPrev.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerPrev.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Next Button

Calendar navigation button. It navigates the calendar one page (12 years by default) in the future.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `nextPage` |  | `((placeholder: DateValue) => DateValue)` | The function to be used for the next page. Overwrites the `nextPage` function set on the Root. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `disabled` | `boolean` | Current disable state |

[YearRangePickerNext.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerNext.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Heading

Heading for displaying the current year range.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `headingValue` | `string` | Current year range heading |

[YearRangePickerHeading.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerHeading.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Grid

Container for wrapping the year range picker grid.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"table"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[YearRangePickerGrid.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerGrid.vue)

| Data attribute | Value |
| --- | --- |
| `[data-readonly]` | Present when readonly |
| `[data-disabled]` | Present when disabled |

### Grid Body

Container for wrapping the grid body.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"tbody"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[YearRangePickerGridBody.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerGridBody.vue)

### Grid Row

Container for wrapping the grid row.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"tr"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[YearRangePickerGridRow.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerGridRow.vue)

### Cell

Container for wrapping the year range picker cells.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"td"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `date*` |  | `DateValue` | The date value for the cell |

[YearRangePickerCell.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerCell.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Cell Trigger

Interactable container for displaying the cell years. Clicking it selects the year.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `year*` |  | `DateValue` | The date value provided to the cell trigger |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `yearValue` | `string` | Current year value |
| `disabled` | `boolean` | Current disable state |
| `selected` | `boolean` | Current selected state |
| `today` | `boolean` | Current year is today's year state |
| `unavailable` | `boolean` | Current unavailable state |
| `highlighted` | `boolean` | Current highlighted state |
| `highlightedStart` | `boolean` | Current highlighted start state |
| `highlightedEnd` | `boolean` | Current highlighted end state |
| `selectionStart` | `boolean` | Current selection start state |
| `selectionEnd` | `boolean` | Current selection end state |

[YearRangePickerCellTrigger.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker/YearRangePickerCellTrigger.vue)

| Data attribute | Value |
| --- | --- |
| `[data-selected]` | Present when selected |
| `[data-value]` | The ISO string value of the date. |
| `[data-disabled]` | Present when disabled |
| `[data-unavailable]` | Present when unavailable |
| `[data-today]` | Present when the year is the current year |
| `[data-selection-start]` | Present when the year is the start of the selection. |
| `[data-selection-end]` | Present when the year is the end of the selection. |
| `[data-highlighted]` | Present when the year is highlighted by the user as they select a range. |
| `[data-highlighted-start]` | Present when the year is the start of the range that is highlighted by the user. |
| `[data-highlighted-end]` | Present when the year is the end of the range that is highlighted by the user. |
| `[data-focused]` | Present when focused |

## Accessibility

### Keyboard Interactions

| Key | Description |
| --- | --- |
| <kbd>Tab</kbd> | When focus moves onto the year range picker, focuses the first navigation button. |
| <kbd>Space</kbd> |  When the focus is on either `YearRangePickerNext` or `YearRangePickerPrev`, it navigates the calendar. Otherwise, it selects the year.  |
| <kbd>Enter</kbd> |  When the focus is on either `YearRangePickerNext` or `YearRangePickerPrev`, it navigates the calendar. Otherwise, it selects the year.  |
| <kbd>ArrowLeft</kbd> / <kbd>ArrowRight</kbd> / <kbd>ArrowUp</kbd> / <kbd>ArrowDown</kbd> | When the focus is on `YearRangePickerCellTrigger`, it navigates the years, changing the page if necessary. |
| <kbd>PageUp</kbd> | When the focus is on `YearRangePickerCellTrigger`, it navigates to the previous page of years. |
| <kbd>PageDown</kbd> | When the focus is on `YearRangePickerCellTrigger`, it navigates to the next page of years. |
| <kbd>Escape</kbd> | Cancels the current range selection and restores the previous valid range. |

---

- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/YearRangePicker)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
