Documentation Index
Fetch the complete documentation index at: https://mintlify.com/motss/app-datepicker/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The app-year-grid component displays a scrollable grid of years for quick year selection. It’s used internally by app-date-picker but can also be used standalone for custom implementations.
Installation
npm install app-datepicker
Import
import 'app-datepicker/app-year-grid';
Or import from specific path:
import 'app-datepicker/dist/year-grid/app-year-grid.js';
Usage
This is a low-level component. Most use cases should use app-date-picker instead.
<app-year-grid></app-year-grid>
<script type="module">
import 'app-datepicker/app-year-grid';
const yearGrid = document.querySelector('app-year-grid');
const currentDate = new Date();
yearGrid.data = {
date: currentDate,
formatters: {
yearFormat: (date) =>
new Intl.DateTimeFormat('en-US', { year: 'numeric' }).format(date)
},
max: new Date('2100-12-31'),
min: new Date('1970-01-01'),
selectedYearLabel: 'Selected year',
toyearLabel: 'Current year',
};
yearGrid.addEventListener('year-updated', (e) => {
console.log('Year selected:', e.detail.year);
});
</script>
Properties
Year grid data object containing all necessary information to render the grid.interface YearGridData {
date: Date; // Currently selected date
formatters: Formatters; // Date formatting functions
max: Date; // Maximum year boundary
min: Date; // Minimum year boundary
selectedYearLabel: string; // Label for selected year
toyearLabel: string; // Label for current year
}
selectedYearGridButton
Promise<HTMLButtonElement | null>
Async query for the currently selected year button element.const selectedButton = await yearGrid.selectedYearGridButton;
if (selectedButton) {
console.log('Selected year:', selectedButton.getAttribute('data-year'));
}
yearGrid
Promise<HTMLDivElement | null>
Async query for the year grid container element.const container = await yearGrid.yearGrid;
Events
year-updated
Fires when a year is selected (clicked or via keyboard).
interface YearUpdatedDetail {
year: number; // Selected year as a number, e.g. 2024
}
yearGrid.addEventListener('year-updated', (event) => {
console.log('Selected year:', event.detail.year);
// Use the year to update other components
const newDate = new Date(event.detail.year, 0, 1);
console.log('First day of year:', newDate);
});
CSS Shadow Parts
app-year-grid::part(year-grid) {
/* Grid container */
padding: 8px;
}
app-year-grid::part(year) {
/* Year button */
font-size: 14px;
padding: 8px 16px;
}
app-year-grid::part(toyear) {
/* Current year */
border: 2px solid currentColor;
font-weight: bold;
}
Available Parts
year-grid - Main grid container
year - Individual year button
toyear - Current year button
Keyboard Navigation
- Arrow Up - Previous row (4 years earlier)
- Arrow Down - Next row (4 years later)
- Arrow Left - Previous year
- Arrow Right - Next year
- Home - First year in range (min)
- End - Last year in range (max)
- Page Up - Previous page (12 years earlier)
- Page Down - Next page (12 years later)
- Enter / Space - Select focused year (native button behavior)
Methods
Protected method for rendering individual year buttons. Can be overridden for customization.interface YearGridRenderButtonInit {
ariaLabel: string;
ariaSelected: 'true' | 'false';
className: string;
part: string;
tabIndex: number;
title?: string;
year: number;
}
Example: Custom Year Range
import 'app-datepicker/app-year-grid';
const yearGrid = document.querySelector('app-year-grid');
const currentYear = new Date().getFullYear();
// Limit to 10 years forward and backward
yearGrid.data = {
date: new Date(),
formatters: {
yearFormat: (date) => date.getUTCFullYear().toString()
},
max: new Date(`${currentYear + 10}-12-31`),
min: new Date(`${currentYear - 10}-01-01`),
selectedYearLabel: 'Selected year',
toyearLabel: 'This year',
};
yearGrid.addEventListener('year-updated', (e) => {
console.log(`User selected: ${e.detail.year}`);
// Validate selection
if (e.detail.year > currentYear + 5) {
alert('Please select a year within 5 years from now');
}
});
Example: Styled Year Grid
<style>
app-year-grid {
--app-primary: #1976d2;
--app-on-primary: white;
}
app-year-grid::part(year-grid) {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 4px;
padding: 16px;
max-height: 300px;
overflow-y: auto;
}
app-year-grid::part(year) {
padding: 12px;
border-radius: 4px;
transition: background 0.2s;
}
app-year-grid::part(year):hover {
background: rgba(25, 118, 210, 0.1);
}
app-year-grid::part(toyear) {
background: #e3f2fd;
border: 2px solid #1976d2;
font-weight: 600;
}
</style>
<app-year-grid></app-year-grid>
Example: Integration with Date Picker
import 'app-datepicker/app-year-grid';
import 'app-datepicker/app-month-calendar';
class CustomDatePicker extends HTMLElement {
#selectedDate = new Date();
#view = 'calendar'; // 'calendar' or 'yearGrid'
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
render() {
this.shadowRoot.innerHTML = `
<button id="toggle-view">Switch to Year Grid</button>
<div id="calendar-view"></div>
<div id="year-view" style="display: none;">
<app-year-grid></app-year-grid>
</div>
`;
}
setupEventListeners() {
const yearGrid = this.shadowRoot.querySelector('app-year-grid');
const toggleBtn = this.shadowRoot.getElementById('toggle-view');
yearGrid.data = {
date: this.#selectedDate,
formatters: {
yearFormat: (date) => date.getUTCFullYear().toString()
},
max: new Date('2100-12-31'),
min: new Date('1970-01-01'),
selectedYearLabel: 'Selected year',
toyearLabel: 'Current year',
};
yearGrid.addEventListener('year-updated', (e) => {
// Update selected date with new year
this.#selectedDate.setUTCFullYear(e.detail.year);
// Switch back to calendar view
this.#view = 'calendar';
this.updateView();
});
toggleBtn.addEventListener('click', () => {
this.#view = this.#view === 'calendar' ? 'yearGrid' : 'calendar';
this.updateView();
});
}
updateView() {
const calendarView = this.shadowRoot.getElementById('calendar-view');
const yearView = this.shadowRoot.getElementById('year-view');
const toggleBtn = this.shadowRoot.getElementById('toggle-view');
if (this.#view === 'yearGrid') {
calendarView.style.display = 'none';
yearView.style.display = 'block';
toggleBtn.textContent = 'Switch to Calendar';
} else {
calendarView.style.display = 'block';
yearView.style.display = 'none';
toggleBtn.textContent = 'Switch to Year Grid';
}
}
}
customElements.define('custom-date-picker', CustomDatePicker);
TypeScript
import type { AppYearGrid } from 'app-datepicker/app-year-grid';
import type { YearGridData } from 'app-datepicker/year-grid/typings';
const yearGrid = document.querySelector('app-year-grid') as AppYearGrid;
const data: YearGridData = {
date: new Date(),
formatters: {
yearFormat: (date: Date) => date.getUTCFullYear().toString()
},
max: new Date('2100-12-31'),
min: new Date('1970-01-01'),
selectedYearLabel: 'Selected year',
toyearLabel: 'Current year',
};
yearGrid.data = data;
yearGrid.addEventListener('year-updated', (e) => {
const year: number = e.detail.year;
console.log(`Selected: ${year}`);
});
Behavior Notes
- The grid displays years in a 4-column layout by default
- Automatically scrolls to show the selected/focused year
- Years are displayed in ascending order (oldest to newest)
- The grid shows all years between
min and max dates
- Uses semantic
<button> elements for accessibility
- Prevents event propagation to work properly within dialogs
- Each button has
tabindex="0" for the focused year, -1 for others
- The component automatically calculates scroll position based on the selected year