Skip to content

fix(layer): mirror anchor-positioned popovers in RTL#3486

Open
AKnassa wants to merge 1 commit into
facebook:mainfrom
AKnassa:fix/3389-dropdown-rtl-popover
Open

fix(layer): mirror anchor-positioned popovers in RTL#3486
AKnassa wants to merge 1 commit into
facebook:mainfrom
AKnassa:fix/3389-dropdown-rtl-popover

Conversation

@AKnassa

@AKnassa AKnassa commented Jul 3, 2026

Copy link
Copy Markdown

What this does

Makes dropdown menus and every other popover open on the correct side for right-to-left languages. Before, a menu in an RTL page opened as if the page were left-to-right — and on some browser versions it landed far away from its button entirely.

Why

Anyone using the design system in an RTL context got menus growing the wrong way or detached from their trigger. Since all popovers share one positioning engine, this was systemic — not just DropdownMenu.

Fixes #3389

What changed

1-before-rtl-wide-menu 2-after-rtl-wide-menu 3-ltr-unchanged 4-after-rtl-story
  • The shared positioning engine (useLayer) now reads the trigger's text direction when a popover opens and mirrors its position accordingly. Works for both ways of setting direction (the dir attribute and the CSS direction property — the latter is what this issue's reproduction uses).
  • An explicit alignment is also set in RTL as a defense for browser versions that mis-handle the implied alignment — that's the "menu appears far from control" case in the report.
  • One fix covers all ~20 popover consumers: DropdownMenu, MoreMenu, Popover, Selector, MultiSelector, Typeahead, DateInput/DateTimeInput/DateRangeInput, SideNav flyouts, TopNav menus, Tooltip/HoverCard (when given side placements), and more.
  • Left-to-right behavior is completely unchanged (existing placement tests pass unmodified; live measurements are byte-identical).
  • 13 new tests covering the RTL matrix and edge cases (direction flips between opens, fixed-mode immunity, indeterminate direction fallback, no-trigger safety, controlled opens), a new RTL Storybook story, docs updated in English/Chinese/dense variants, and a changeset.

How to see it

Run Storybook and open Core/DropdownMenu → RTL: both menus (one per direction mechanism) open right-aligned to their trigger and grow left. Compare with any other DropdownMenu story for the unchanged LTR behavior. Screenshots attached below.

Good to know (scope)

  • The reported "far from control" displacement does not reproduce on current Chrome (it conforms to spec here); the explicit-alignment part of the fix defends against the engine class that shows it. The issue's Environment field is empty — reporter's browser/version would be useful to confirm.
  • Known follow-ups deliberately not in this PR: Tokenizer positions its popover through a separate code path with a physical left: anchor(start) (still RTL-wrong; this PR only guards it), side-placement entry animations still slide from the physical side (cosmetic), and layers opened by timers may paint their very first RTL open one frame early (bounded; tooltips' centered default is unaffected).

getPositionArea mapped the logical placement/alignment API to physical
position-area keywords with no direction awareness, so every context-mode
popover (DropdownMenu, MoreMenu, Selector, Typeahead, date inputs, nav
menus) opened toward the physically-LTR side under RTL — and on engines
that mis-resolve position-area's implied alignment via the popover's
inherited direction, the menu landed at the viewport mirror of its
trigger ('far from control').

useLayer now resolves the trigger's computed direction at show() time
(sanctioned getComputedStyle pattern — works for both the CSS direction
property and the dir attribute), mirrors the physical keywords under
RTL, and emits an explicit physical justify-self in RTL only to remove
the engine's direction-sensitive implied-alignment resolution. LTR
output is byte-identical. Tokenizer and Carousel null the RTL
justify-self defensively (they override positioning inline).

Logical placement semantics documented across useLayer/Popover/Tooltip/
HoverCard docs (en/dense/zh).
@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

@AKnassa is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jul 3, 2026
@AKnassa AKnassa marked this pull request as ready for review July 3, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Dropdown broken if RTL

1 participant