Problem
useDirection() currently falls back to 'ltr' when no DirectionProvider exists in the React tree:
// packages/react/direction/src/direction.tsx
function useDirection(localDir?: Direction) {
const globalDir = React.useContext(DirectionContext);
return localDir || globalDir || 'ltr'; // ← hardcoded fallback
}
This means every Radix component renders dir="ltr" on its DOM elements — ignoring <html dir="rtl"> entirely.
Real-world impact
We discovered this while contributing Arabic/RTL support to AFFiNE (65k+ GitHub stars). Even after correctly setting <html lang="ar" dir="rtl"> at the document level, every Radix dropdown, dialog, popover, and scroll area continued to render dir="ltr" — effectively overriding the document direction.
The workaround: manually wrap the entire app in DirectionProvider with a MutationObserver. This works, but it requires every application to implement this boilerplate. With 130M+ monthly downloads and Radix powering shadcn/ui (used by Vercel, Linear, Supabase), the RTL community repeats this fix across every project.
Proposed fix
function useDirection(localDir?: Direction) {
const globalDir = React.useContext(DirectionContext);
const documentDir =
typeof document !== 'undefined'
? document.documentElement.dir === 'rtl' ? 'rtl' : 'ltr'
: 'ltr';
return localDir || globalDir || documentDir;
}
Why this is safe
- No breaking changes:
DirectionProvider still takes precedence — existing apps are unaffected
- LTR apps unchanged: Most apps don't set
<html dir="rtl">, so documentDir defaults to 'ltr'
- SSR safe:
typeof document !== 'undefined' guard handles server-side rendering
- Dynamic: Works with runtime language switching (when
dir changes on <html>)
- Zero configuration: RTL apps work correctly without any wrapper
Who this helps
Arabic, Hebrew, Persian, and Urdu speakers — ~500 million people. Every app using Radix that sets <html dir="rtl"> currently has broken RTL layout for dropdowns, dialogs, and popovers.
Context
- Validated during AFFiNE Arabic localization: PR #14646
- shadcn added RTL support in January 2026 — this change would make it automatic for all Radix consumers
- The fix is a single line change in one file
Problem
useDirection()currently falls back to'ltr'when noDirectionProviderexists in the React tree:This means every Radix component renders
dir="ltr"on its DOM elements — ignoring<html dir="rtl">entirely.Real-world impact
We discovered this while contributing Arabic/RTL support to AFFiNE (65k+ GitHub stars). Even after correctly setting
<html lang="ar" dir="rtl">at the document level, every Radix dropdown, dialog, popover, and scroll area continued to renderdir="ltr"— effectively overriding the document direction.The workaround: manually wrap the entire app in
DirectionProviderwith aMutationObserver. This works, but it requires every application to implement this boilerplate. With 130M+ monthly downloads and Radix powering shadcn/ui (used by Vercel, Linear, Supabase), the RTL community repeats this fix across every project.Proposed fix
Why this is safe
DirectionProviderstill takes precedence — existing apps are unaffected<html dir="rtl">, sodocumentDirdefaults to'ltr'typeof document !== 'undefined'guard handles server-side renderingdirchanges on<html>)Who this helps
Arabic, Hebrew, Persian, and Urdu speakers — ~500 million people. Every app using Radix that sets
<html dir="rtl">currently has broken RTL layout for dropdowns, dialogs, and popovers.Context