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.