Skip to content

RTL Support

How Cynosure handles right-to-left layouts using logical CSS properties and DirectionProvider.

Cynosure is RTL-safe by construction. The rules:

  1. Every internal .css.ts uses logical CSS properties (padding-inline, margin-inline, inset-inline, border-inline-end, …). Physical *-left / *-right declarations live only in the public LayoutProps escape hatch and in two deliberately-physical files documented in the RTL audit.
  2. Icons that imply direction (chevrons, arrows, indicators) mirror via transform: scaleX(-1) when the document direction flips.
  3. Focus-order and tab sequence are unaffected by direction — the document still flows from first to last.

Wrap your app in DirectionProvider:

import { DirectionProvider } from '@arshad-shah/cynosure-react';
<DirectionProvider dir="rtl">
{children}
</DirectionProvider>

This sets dir="rtl" on the wrapping element and exposes a useDirectionContext() hook every Cynosure component reads. Arrow-key navigation in Tabs, RadioGroup, ToggleGroup, the menu family, and NavigationMenu swaps the next/prev semantics so visual “right” always matches the reading order.

Nest another DirectionProvider:

<DirectionProvider dir="rtl">
<ArabicChrome>
<DirectionProvider dir="ltr">
<EnglishExcerpt />
</DirectionProvider>
</ArabicChrome>
</DirectionProvider>

Each subtree resolves its own direction.

If you need a physical property at the call site (e.g. “always add 8px to the left”), use the LayoutProps escape hatch:

<Box paddingLeft="2">Physical padding — will NOT flip in RTL.</Box>

Prefer the logical variants (paddingStart, paddingInline) unless you are deliberately opting out.

pnpm audit:rtl walks every .css.ts in packages/react/src and fails if it finds a physical *-left / *-right declaration outside the allowlist. Run it locally before pushing RTL-sensitive changes.