All case studies

Munch · Shared component library

Date Range Picker

A calendar component that turned out to be a product.

My role
Sole owner — design, implementation, accessibility, shared-library release
Stack
ReactTypeScriptdate-fns-tzTailwind CSSStorybook

The problem

Reporting across the platform needed date selection — and nothing off the shelf fit. The requirement wasn't “pick a day.” It was: pick a range, pick a time on each end, do it correctly in South African time regardless of where the browser thinks it is, work on a phone, and stay keyboard-navigable.

This was the first component I owned end to end. It had to be right, because every report in the system would depend on it.

What I built

  • Dual-calendar range selection with hover preview, so the range you're about to select is visible before you commit to it.
  • Time selection on both ends of the range, with previously chosen times preserved when the date changes — a small detail that removes a genuinely annoying re-entry step.
  • Quick-select presets (Today, Yesterday, Last 7 Days, Last 30 Days) for the 90% case, with the full calendar there for the rest.
  • Month and year dropdowns, so navigating back a year isn't twelve clicks.
  • Explicit timezone handling via date-fns-tz — dates are pinned to Africa/Johannesburg rather than inherited from the browser, so a franchisee's report reads the same whether they open it in Pretoria or on holiday abroad.
  • A responsive layout that collapses to a single calendar with a mobile-appropriate quick-select on small screens.
  • An accessibility pass on ARIA roles and keyboard navigation after an initial review flagged gaps.

What was hard

Timezones. The naive approach — manually calculating offsets — falls apart at DST boundaries and when the browser's local time disagrees with the business's time. The working solution was to stop fighting JavaScript's Date object: read the date components in the target timezone, apply the change there, and convert back to UTC through date-fns-tz rather than doing arithmetic by hand.

The other hard part was architectural. It's tempting to build a date picker as one component. It isn't one — it's a controlled input, a calendar, a time select, a month/year navigator, and a quick-select panel, all sharing state. Splitting it into sub-components with a single source of truth is what made it maintainable.

Outcome

Shipped as a shared library component and used across reporting and admin surfaces. Supports both single-date and range modes from the same API.