Skip to content

fix: render an independent, panel-aware dropdown on every month header - #88

Open
balajis-qb wants to merge 1 commit into
mainfrom
issue-6320/fix/multi-month-header-height
Open

fix: render an independent, panel-aware dropdown on every month header#88
balajis-qb wants to merge 1 commit into
mainfrom
issue-6320/fix/multi-month-header-height

Conversation

@balajis-qb

Copy link
Copy Markdown
Collaborator

Description

Linked issue: Hacker0x01#6320

Problem

With showYearDropdown (or showMonthDropdown / showMonthYearDropdown) combined with monthsShown > 1, only the first month panel rendered the dropdown control in its header (renderYearDropdown(i !== 0) etc. suppressed it on every other panel). .react-datepicker__header__dropdown has no explicit height in datepicker.scss, so on the panels that didn't render a dropdown it collapsed to 0 height instead of reserving the same space — making month 1's header taller than the others and misaligning the day grids underneath, since each .react-datepicker__month-container is floated independently with no shared grid row.

We tried three approaches before landing on this one:

  1. Hardcoded CSS min-height — the actual rendered height of a native form control genuinely differs by browser/OS/zoom, so any hardcoded pixel value is just a future bug waiting for a different browser.
  2. ResizeObserver-based runtime measurement — technically correct and browser-agnostic, but added a ref/observer/lifecycle/state footprint to calendar.tsx for what turned out to be solvable without any of it, plus a first-paint flash before the first measurement landed.
  3. Render the same dropdown on every panel but mark the extras inert/visibility: hidden — closer, but requires every dropdown component to keep honoring a "pretend this doesn't exist" contract for every future interactive element added inside it. Already surfaced one bug from exactly that shape during development (a read-view <button>'s own inline visibility style winning over the ancestor's hidden in "scroll" mode).

Changes

  • Every shown month panel now renders its own real, independently interactive dropdown, bound to that panel's own displayed month/year — not a hidden/inert copy. Since every header renders identical live control markup, header heights match by construction on any browser, with no hardcoded number and no runtime measurement.
  • changeYear/changeMonth/changeMonthYear in calendar.tsx now accept the triggering panel's date (and, for month/month-year, monthSelectedIn) instead of always acting on the calendar's anchor date:
    • changeYear shifts the anchor by the picked year delta, so every panel keeps its own month and the whole view moves together.
    • changeMonth/changeMonthYear land the result on the panel that was actually interacted with (reusing the existing monthSelectedIn plumbing day selection already relies on), instead of always resetting to the leftmost panel.
  • renderCustomHeader consumers are unaffected — they still receive the unbound changeMonth/changeYear and call them with a single argument, so the new parameters fall back to their defaults and reproduce the exact previous anchor-based, leftmost-panel-landing behavior. Verified this explicitly with a temporary regression test exercising both panels' controls before committing (removed once confirmed, since it duplicated existing coverage).
  • Updated/added tests in calendar_test.test.tsx and multi_month_test.test.tsx: dropdown containers now assert one per panel (not one total), plus new behavioral tests picking a year/month/month-year from a non-first panel and asserting the whole multi-month view updates correctly.

Open question for maintainers: the original design intentionally restricted dropdowns to the first month, treating N simultaneous interactive dropdowns as ambiguous about "which one's in charge." This PR resolves that ambiguity with explicit semantics (delta-shift on year, land-on-interacted-panel on month/month-year) rather than avoiding it — curious if there was a specific reason (e.g. an accessibility concern with multiple same-labeled comboboxes) behind the original restriction that isn't captured in the linked issues (Hacker0x01#4222, Hacker0x01#790), since that would shape whether this is the right direction.

Contribution checklist

  • I have followed the contributing guidelines.
  • I have added sufficient test coverage for my changes.
  • I have formatted my code with Prettier and checked for linting issues with ESLint for code readability.

showYearDropdown/showMonthDropdown/showMonthYearDropdown only rendered
their control on the first month panel in monthsShown > 1 mode, so
every other panel's header collapsed to a shorter height than the
first - browsers render native form controls (select/button) at
different heights, so no fixed or measured placeholder height reliably
matched it across browsers/OS/zoom.

Render the same live dropdown on every panel instead of reserving its
space. Every header now renders identical control markup, so heights
match by construction on any browser, with no hardcoded number and no
runtime measurement.

This requires each dropdown to be genuinely interactive per panel
rather than a hidden/inert placeholder, so changeYear/changeMonth/
changeMonthYear now take the triggering panel's date and land the
result accordingly instead of always acting on the calendar's anchor
date:
- changeYear shifts the anchor by the picked year delta so every panel
  keeps its own month and moves together.
- changeMonth/changeMonthYear land the result on the panel that was
  interacted with (via the existing monthSelectedIn plumbing used for
  day selection), instead of always resetting to the leftmost panel.

Custom headers (renderCustomHeader) are unaffected: they still receive
the unbound changeMonth/changeYear and call them with a single
argument, so the new panelDate/monthSelectedIn parameters fall back to
their defaults and reproduce the exact previous anchor-based,
leftmost-panel-landing behavior - verified with a temporary regression
test exercising both panels' controls before this commit.

Fixes Hacker0x01#6320

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@balajis-qb
balajis-qb force-pushed the issue-6320/fix/multi-month-header-height branch from 687ba81 to f37cce6 Compare August 14, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant