Skip to content

fix(DateRangePicker): auto-flip popup when it would overflow viewport#232

Merged
wreiske merged 1 commit into
mainfrom
fix/date-range-picker-overflow
May 14, 2026
Merged

fix(DateRangePicker): auto-flip popup when it would overflow viewport#232
wreiske merged 1 commit into
mainfrom
fix/date-range-picker-overflow

Conversation

@wreiske
Copy link
Copy Markdown
Member

@wreiske wreiske commented May 14, 2026

Summary

Adds an align prop to DateRangePicker and auto-flips the popup when the default left-aligned position would overflow the viewport.

Why

The desktop calendar popup is always rendered with absolute top-full left-0, so when the trigger sits in a right-aligned slot (e.g. a page header's actions area) the popup spills past the right edge of the viewport and gets clipped.

What changed

  • New align?: 'start' | 'end' | 'auto' prop on DateRangePicker, default 'auto'.
    • 'start': original behavior — popup left edge at trigger left edge.
    • 'end': popup right edge at trigger right edge.
    • 'auto': starts at 'start' and, after open, measures the trigger and flips to 'end' when the popup would overflow the viewport on the right.
  • Auto-flip uses a useLayoutEffect and triggerRef.getBoundingClientRect() so it runs before paint, no visible jump.
  • Estimated popup width accounts for the optional preset sidebar (showPresets).

Backward compatibility

Default switches from "always left" to "auto", but auto only flips when the original behavior would actually overflow. Existing usages on the left side of layouts render identically. Consumers can pin to the old behavior with align="start".

Tested

  • Verified in production on hum.bluehive.com analytics — picker now stays fully on screen when placed in a right-aligned page header.
  • Storybook stories continue to render correctly.

Adds an `align` prop ('start' | 'end' | 'auto', default 'auto') that
controls the horizontal alignment of the desktop calendar popup. Under
'auto' we measure the trigger after open and flip from left-aligned to
right-aligned when the popup would otherwise spill past the right edge
of the viewport.

Fixes the picker being clipped off the page when the trigger sits in a
right-aligned slot (e.g. a page header's actions area).
Copilot AI review requested due to automatic review settings May 14, 2026 21:53
@wreiske wreiske merged commit bba5e4c into main May 14, 2026
9 of 10 checks passed
@wreiske wreiske deleted the fix/date-range-picker-overflow branch May 14, 2026 21:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an align prop ('start' | 'end' | 'auto', default 'auto') to DateRangePicker to prevent the desktop calendar popup from overflowing the right edge of the viewport when the trigger sits in a right-aligned slot. Auto mode measures the trigger via useLayoutEffect and flips to right-edge alignment when needed.

Changes:

  • New align prop with 'auto' default; resolved alignment tracked in state.
  • useLayoutEffect measures the trigger and flips to 'end' when the estimated popup width (840px with presets, 640px without) would overflow.
  • Popup container conditionally uses right-0 or left-0.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/components/DateRangePicker/DateRangePicker.tsx Adds align prop, auto-flip layout effect, and conditional right-0/left-0 class on popup.
package.json Version bump from 0.5.0 to 0.6.1.
Comments suppressed due to low confidence (1)

src/components/DateRangePicker/DateRangePicker.tsx:430

  • Popup width is hardcoded (200px sidebar + ~640px calendar panel). If the calendar's actual rendered width changes (e.g., due to font scaling, locale-specific month/weekday labels, or future style adjustments to padding/columns), the flip threshold will drift out of sync with reality. Consider measuring the popup's actual width via calendarRef.current.getBoundingClientRect() after it mounts to make the heuristic robust to layout changes.
    // Approximate popup width: preset sidebar (200px) + dual calendar panel
    // (~640px including padding). Slight overestimate is fine — we just want
    // to flip when 'start' alignment would clearly overflow.
    const estimatedPopupWidth = showPresets ? 840 : 640;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +417 to +436
React.useLayoutEffect(() => {
if (isMobileVariant || !isCalendarOpen) return;
if (align === 'start' || align === 'end') {
setResolvedAlign(align);
return;
}
if (typeof window === 'undefined') return;
const trigger = triggerRef.current;
if (!trigger) return;
const rect = trigger.getBoundingClientRect();
// Approximate popup width: preset sidebar (200px) + dual calendar panel
// (~640px including padding). Slight overestimate is fine — we just want
// to flip when 'start' alignment would clearly overflow.
const estimatedPopupWidth = showPresets ? 840 : 640;
const margin = 8;
const overflowsRight =
rect.left + estimatedPopupWidth > window.innerWidth - margin;
const fitsLeftAligned = rect.right - estimatedPopupWidth >= margin;
setResolvedAlign(overflowsRight && fitsLeftAligned ? 'end' : 'start');
}, [align, isCalendarOpen, isMobileVariant, showPresets]);
Comment thread package.json
{
"name": "@mieweb/ui",
"version": "0.5.0",
"version": "0.6.1",
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.

2 participants