The picker has three layers of responsiveness: viewport-tier modal widths, container-query progressive inner content, and a stable flex-column scroll layout. They work together so a 6-month grid picker behaves correctly from a phone all the way to a 4K display.

This page is about behavior. For when to pick which positioning mode, see Positioning Modes.

RB01 Modal Width Tiers

The modal's outer width adapts to viewport size via four CSS variables

Tiers
TierViewportDefaultVariable
xs≤ 480pxcalc(100vw − 2 × gap)--drp-modal-width-xs
sm481–768pxcalc(100vw − 2 × gap)--drp-modal-width-sm
md769–1200px900px--drp-modal-width-md
lg≥ 1201px1100px--drp-modal-width-lg

Breakpoints align with the rest of the codebase (480 / 768 / 1200, same as _base.css and the Responsive Sizing demo's --drp-rem scaling).

Override CSS
CSS
 
Details
Why Hardcoded Breakpoints?

CSS media queries cannot read CSS variables, so the breakpoints themselves are hardcoded in _modal.css. Only the widths inside each rule are variable-driven. To shift breakpoints, edit _modal.css directly.

Other Modal Hooks
  • --drp-modal-gap — viewport-edge gap (default 16px)
  • --drp-modal-backdrop-bg — scrim color (default rgba(0, 0, 0, 0.45))
  • --drp-modal-transition — fade timing (default 150ms ease-out)
  • --drp-z-index-modal / --drp-z-index-modal-backdrop

RB02 Progressive Inner-Content Layout

The visible month count adapts to the modal's actual width via CSS container queries

Tiers
Modal widthFlex layout (single row)Grid layout
≤ 600px1 month visible1 column (siblings hidden)
601–900px2 months visible2 columns, all months visible (wraps to more rows)
901–1200px3 months visibleup to 3 columns (capped from configured)
> 1200pxConfigured countConfigured grid as-is

Driven by @container drp-modal (...) rules in _modal.css — no JS state changes, no rebuild on resize.

Notes
Why grid keeps all months visible: a 2×3 configuration is a deliberate layout choice — collapsing it to "show fewer months" would surprise the user. Instead, narrow grid modals just stack the same months into more rows (2×3 → 3×2 at 601–900px, etc.). Only at the very narrow ≤600px tier do we hide siblings, since 6 months stacked vertically would be unusably tall on a phone.
Hidden columns still update. When sibling months are hidden via CSS, they still update in lockstep through the existing collision-resolve navigation logic. Range selection across "more months than are visible" continues to work — the user just navigates time linearly with the visible month's prev/next.
Details
Container vs Viewport Thresholds

The thresholds for inner content are based on the modal's actual width, not the viewport. So a desktop user who overrode --drp-modal-width-lg to 700px would still get 2-column behavior even on a 1920px monitor — because 600px ≤ 700px ≤ 900px puts them in the 2-column tier.

RB03 Stable Calendar Height (Always-6-Week Rendering)

Every month renders 6 weeks (42 cells) regardless of how many weeks it actually fits in

Why

Without this, a month that fits in 5 weeks (e.g., October 2026) would leave empty space at the bottom when laid out next to a 6-week month (e.g., November 2026) in a grid — rows equalize to the tallest item. The visible result was a "gap" between the day grid and the next element.

Now every month renders exactly 42 cells, spilling into the previous/next month for partial rows. Same height every time.

Effect
This is the standard convention used by most date pickers (Google, Apple, Bootstrap datepicker). Clicking through months no longer makes the calendar jump in size.
Details
Side Effect

Single-month inline pickers now show one extra row of dimmed --other-month days. That's universally accepted in date-picker UI but is a behavioral change from earlier versions.

RB04 Flex-Column Scroll Layout

Inside floating and modal pickers, only the months area scrolls — header and action bar stay pinned

Architecture

Calendars in non-inline modes are now display: flex; flex-direction: column; overflow: hidden. The months area is the only scrollable region; the unified header, per-month headers, summary, and action bar are all flex-shrink: 0 so they don't move.

Side benefit: the action bar (Today / Clear / Apply) is always visible regardless of how tall the multi-month content is.

Sticky regions
CSS
 
Details
Sticky Per-Month Headers

The per-month header (month name + prev/next, or static label in unified-navigation mode) is position: sticky; top: 0 within the scrolling months area:

  • Single-month layouts: header always pinned at the top, days scroll under it.
  • Horizontal multi-month layouts: all headers stick simultaneously and form a continuous header strip.
  • Grid layouts: each row's headers stick while that row is being scrolled past, then unstick when the row is fully gone (stacked-sticky behavior).