Date picker
A month calendar built from year and month in state. A days() method
generates the grid — leading blanks plus each day’s ISO string — so prev/next
month is just arithmetic on two numbers.
Markup
<button @click="prevMonth" aria-label="Previous month">‹</button>
<span data-text="monthLabel()"></span>
<button @click="nextMonth" aria-label="Next month">›</button>
<template data-each="days()" data-key="key">
<div>
<button data-show="item.day > 0" @click="pick" data-bind="class:dayClass(item), data-iso:item.iso" data-text="item.day"></button>
</div>
</template>
<p data-text="selected ? ('Selected: ' + selected) : 'Pick a date'"></p>
Component
Micra.define("datepicker", {
state: { year: 2026, month: 5, selected: "" },
monthLabel() {
const m = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
return m[this.state.month] + " " + this.state.year;
},
days() {
const { year, month } = this.state;
const startDow = (new Date(year, month, 1).getDay() + 6) % 7; // Monday-first
const dim = new Date(year, month + 1, 0).getDate();
const cells = [];
for (let i = 0; i < startDow; i++) cells.push({ key: "b" + i, day: 0 });
for (let d = 1; d <= dim; d++) {
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
cells.push({ key: iso, day: d, iso });
}
return cells;
},
dayClass(cell) {
const base = "h-9 w-9 rounded-md text-sm ";
return base + (cell.iso === this.state.selected ? "bg-indigo-600 text-white" : "hover:bg-zinc-100");
},
pick(e) {
this.state.selected = e.currentTarget.dataset.iso;
},
prevMonth() {
if (this.state.month === 0) {
this.state.month = 11;
this.state.year--;
} else {
this.state.month--;
}
},
nextMonth() {
if (this.state.month === 11) {
this.state.month = 0;
this.state.year++;
} else {
this.state.month++;
}
},
});
Each cell carries a stable key (its ISO date, or b0/b1 for the leading
blanks), so the keyed diff swaps only the cells that change when you page months.