Skip to the solution
HardMachine Coding14 min read

Build a Calendar / Date Picker

1.1k views

The problem

Question presented to candidate: "Build a date picker for our booking form, without a date library. A button shows the chosen date; clicking it opens a calendar for one month. The user can move between months and years, pick a day, and do all of it from the keyboard. Dates before a minimum must not be selectable, and today should stand out."

Requirements:

  • A trigger button that opens a popup calendar and shows the selected date in words.
  • A month grid with weekday headers, always 6 rows of 7 days, including leading and trailing days of the neighbouring months.
  • Previous and next month and year buttons, disabled when the whole target month is out of range.
  • Today highlighted, the selected day marked, days outside min / max disabled.
  • Keyboard: arrows move by day and week, Home / End to the week edges, PageUp / PageDown by month, Shift+PageUp / PageDown by year, Enter or Space to select, Escape to close.
  • Focus moves into the grid on open and returns to the trigger on close; clicking outside closes the popup.

What a strong answer should cover:

  • Representing a calendar date without a time zone (an ISO YYYY-MM-DD string or a year/month/day triple), and doing day arithmetic through Date.UTC or the month-overflow trick, never by adding 86400000 ms to a local midnight.
  • Grid generation: leading blanks from the weekday of the 1st, month lengths and leap years from new Date(y, m + 1, 0), a fixed 42-cell grid.
  • Keyboard grid navigation with a roving tabindex, and moving DOM focus after the re-render.
  • The WAI-ARIA date picker dialog pattern: role="dialog", role="grid", aria-selected, aria-current="date", a live month heading, a focus trap and focus return.
  • Clamping: month jumps from the 31st land on the last day of a shorter month, and focus never leaves min / max.

Clarifying questions expected:

  • "Which day does the week start on, and do we need locales other than English?"
  • "Should picking a day close the popup, or is there an OK button?"
  • "Can the user type a date as well, or only pick one?"

Code / implementation expected: Yes. A working component with the date helpers, the grid, keyboard handling and focus management.

  • React
  • Dates
  • UI

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

14 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useState } from "react";
import DatePicker from "./src/components/DatePicker";

const css = `
  body { margin: 0; background: #0f1115; color: #e6e6e6; font-family: system-ui, sans-serif; }
  .page { max-width: 420px; margin: 0 auto; padding: 24px 16px; }
  .dp { position: relative; display: flex; flex-direction: column; gap: 6px; }
  .dp-label { font-size: 13px; color: #9aa4b2; }
  .dp-trigger { text-align: left; padding: 10px 12px; border-radius: 8px; border: 1px solid #2c3340;
    background: #171a21; color: inherit; font: inherit; cursor: pointer; }
  .dp-pop { position: absolute; top: 100%; left: 0; margin-top: 6px; z-index: 10; width: min(320px, 100%);
    background: #171a21; border: 1px solid #2c3340; border-radius: 12px; padding: 12px; box-shadow: 0 10px 30px #0008; }
  .dp-head { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
  .dp-head h2 { flex: 1; text-align: center; font-size: 15px; margin: 0; }
  .dp-head button { background: none; border: 0; color: #c9d1d9; font-size: 18px; width: 32px; height: 32px; border-radius: 6px; cursor: pointer; }
  .dp-head button:disabled { opacity: .3; cursor: default; }
  table { width: 100%; border-collapse: collapse; }
  th { font-size: 12px; color: #8b949e; font-weight: 500; padding: 4px 0; }
  td.day { text-align: center; padding: 8px 0; border-radius: 8px; cursor: pointer; font-size: 14px; }
  td.day:hover { background: #222834; }
  td.day:focus { outline: 2px solid #f9a825; outline-offset: -2px; }
  td.outside { color: #5d6573; }
  td.today { font-weight: 700; color: #f9a825; }
  td.selected { background: #f9a825; color: #1c140a; }
  td.disabled { color: #3d434d; cursor: not-allowed; text-decoration: line-through; }
  .out { margin-top: 16px; font-size: 14px; color: #9aa4b2; }
`;

export default function App() {
  const [date, setDate] = useState("2024-02-10");
  return (
    <main className="page">
      <style>{css}</style>
      <DatePicker
        label="Check-in date"
        value={date}
        onChange={setDate}
        min="2024-02-05"
        max="2027-12-31"
      />
      <p className="out" data-testid="out">
        Selected: {date || "none"}
      </p>
    </main>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 83 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

Build a Kanban board with drag and drop

Continue