Skip to content

cat-dropdown / cat-datepicker: render popups in the top layer (fix clipping in modals)#54

Merged
drewda merged 2 commits into
mainfrom
popup-top-layer
Jun 11, 2026
Merged

cat-dropdown / cat-datepicker: render popups in the top layer (fix clipping in modals)#54
drewda merged 2 commits into
mainfrom
popup-top-layer

Conversation

@drewda

@drewda drewda commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

A dropdown menu or datepicker calendar opened inside a scrollable container (most visibly a cat-modal body, which now has overflow: auto) was clipped at the container's edge. This affects real usage: CALACT's Feed Archive modal (interline-io/calact-network-analysis-tool#390) composes datepickers inside a modal, so the calendar was cut off. cat-tooltip solved the same class of problem in 0.3.0 with the Popover API; this brings cat-dropdown and cat-datepicker in line.

Changes

  • New src/util/anchored-popover.ts composable. When the Popover API is available it sets popover="manual" on the popup, shows it with showPopover(), and positions it with fixed viewport coordinates computed from the trigger's bounding box. The top layer escapes ancestor overflow clipping, z-index stacking, and transformed containing blocks. manual (not auto) so the popup does not light-dismiss outside the components' own Escape/click-outside handling.
  • The popup stays in place in the DOM (the Popover API renders in the top layer without moving the element), so scoped styles, aria-controls/aria-activedescendant, focus management, and click-outside containment via root.contains() are all unchanged.
  • Vertical-side flip when the preferred side lacks room, viewport clamping on both axes, and reposition on scroll (capture phase, so scrolling any ancestor works) and resize.
  • Browsers without the Popover API (and jsdom) fall back to the existing absolute positioning; no behavior change there, and all existing widget tests pass unchanged.
  • The positioning math is a pure exported function computePopoverPosition with 8 unit tests (alignment, flip both directions, no-flip, horizontal clamp, left-margin clamp, oversized clamp).

Test plan

  • In the playground, open the modal layered-Escape demo (/controls/modal) and open the dropdown and datepicker inside it: the menu and calendar should render fully, not clipped by the modal body.
  • Open a datepicker near the bottom of the viewport: the calendar should flip above the input.
  • Open a bottom-right-positioned dropdown: the menu should right-align to the trigger.
  • Scroll the page with a popup open: it should track the trigger.
  • Confirm standalone (non-modal) dropdowns/datepickers still open, position, and dismiss correctly.

Generated with Claude Code

The menu and calendar were clipped by any ancestor with overflow
auto/hidden, most visibly a scrollable modal body. Render them in the
browser top layer via the Popover API (like cat-tooltip since 0.3.0)
through a new useAnchoredPopover composable: showPopover with fixed
viewport coordinates, vertical flip when the preferred side lacks room,
viewport clamping, and reposition on scroll/resize. The element stays
in place in the DOM, so scoped styles, ARIA relationships, focus
management, and click-outside containment are unchanged. Browsers
without the API keep the absolute-positioning fallback. The positioning
math is a pure, unit-tested function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying catenary with  Cloudflare Pages  Cloudflare Pages

Latest commit: f5e89cd
Status: ✅  Deploy successful!
Preview URL: https://be6d470c.catenary-5bw.pages.dev
Branch Preview URL: https://popup-top-layer.catenary-5bw.pages.dev

View logs

@drewda drewda merged commit 3ad066c into main Jun 11, 2026
6 checks passed
@drewda drewda deleted the popup-top-layer branch June 11, 2026 17:09
@github-actions github-actions Bot mentioned this pull request Jun 11, 2026
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