Right to left (RTL) & localization
BeeUI supports right to left (RTL) layout through one shared, stateless direction resolver rather than each component reading the platform independently. This is ADR-004: Direction architecture in the source repository, implemented in use-direction.ts (@beemvp/beeui-ui).
If you are adding right to left support to an application, set the host platform’s direction authority and let BeeUI read it; BeeUI does not create a second RTL state system.
Prerequisites: control over your app’s direction authority (I18nManager.forceRTL on
native, the document dir attribute on Web) and an RTL locale or manual override to test
against.
How direction is resolved
Section titled “How direction is resolved”For every direction-aware component, the effective direction is:
- an explicit
directionprop, when a caller supplies one; - otherwise the platform’s own ambient authority —
I18nManager.isRTLon iOS/Android, ordocument.documentElement.dir === 'rtl'on Web; - otherwise
'ltr'.
BeeUI never calls I18nManager.forceRTL() and never writes the DOM dir attribute —
setting the app’s direction stays the host application’s responsibility. BeeUI only reads
the existing authority and forwards it, the same pattern already established for theme
scope: no second global state engine, no context provider, no subscription store dedicated
to RTL.
Because there is no live subscription, a Web document.dir change is reflected the next
time an affected component re-renders (not instantly, without an app-triggered
re-render); a native I18nManager.forceRTL() change takes effect after the app reloads.
This is a documented, accepted limitation, not a defect.
What resolves direction today
Section titled “What resolves direction today”Popover, DropdownMenu, Select, and Tooltip — every anchored-overlay component —
call the same resolver instead of each duplicating the platform read. Breadcrumb,
Pagination, Table, and Calendar also call it directly for their own logical
start/end layout (separator glyphs, previous/next chevrons, column order, and
navigation-chevron/arrow-key mirroring, respectively).
Concretely:
- Pagination points “previous” toward the logical start and “next” toward the logical end, mirroring the rendered chevron glyphs under RTL.
- Breadcrumb mirrors its default separator glyph under RTL while still honoring an explicit caller-supplied separator unchanged.
- Table (
layout="scroll") adoptsdir="rtl"on its scroll wrapper and visually reverses column order under RTL, verified against real rendered DOM order, not just a flipped prop. - Calendar mirrors ArrowLeft/ArrowRight keyboard navigation and its navigation chevrons to match real RTL layout — verified against actual rendered geometry with a real browser, not only a unit-level assertion.
- Sheet and Tooltip remain fully operable (dismissible, keyboard-reachable) when the document direction is RTL.
Known gaps
Section titled “Known gaps”RTL is implemented and exercised per-component with real evidence (deterministic
precedence tests plus Chromium Playwright tests for Table, Calendar, Sheet, and Tooltip),
but BeeUI does not yet have a single cross-cutting RTL acceptance matrix the way it has one
for keyboard/focus (docs/keyboard-focus-acceptance-matrix.md, #146). That consolidation
is tracked as open work in BeeUI issues #141 (RTL overlay acceptance) and #142 (RTL
component stress matrix). Localized/long-content stress testing (CJK, long translated
strings, etc.) beyond BeeUI’s existing Dynamic Type wrap-vs-truncation policy is tracked
separately and also remains open (#144).
The full, per-component RTL evidence index lives in docs/accessibility-contract.md and
docs/decisions/004-direction-architecture.md in the source repository.