Direction (RTL)

How SubstrateUI supports right-to-left layout, what is handled automatically, and where consumers still need to make choices per usage.

Why RTL matters

The web serves users in roughly twenty right-to-left languages — Arabic, Hebrew, Persian, Urdu, and others. For those users, layout should flip: reading flow runs from right to left, controls sit on the opposite edge, icons pointing forward in LTR point backward in RTL, and whole pages read natively rather than as translated-but- mirrored LTR interfaces. RTL is a first-class direction in SubstrateUI, not an afterthought.

How to enable RTL in your app

Set dir on the <html> element and wrap your app in DirectionProvider so Radix-based primitives pick up the direction:

import { DirectionProvider } from "@substrateui/core"

export default function App({ children }: { children: React.ReactNode }) {
  return (
    <html dir="rtl">
      <body>
        <DirectionProvider dir="rtl">
          {children}
        </DirectionProvider>
      </body>
    </html>
  )
}

Setting dir on <html> — rather than on a wrapper div — ensures that native HTML elements and Radix portals (which render outside the React tree at the document body) also inherit the direction. The DirectionProvider is what Radix primitives read to decide which arrow keys advance focus, which side a menu opens from, and so on.

How the system supports RTL

SubstrateUI components use logical CSS properties throughout — ps-*/pe-*, ms-*/me-*, start-*/end-*, border-s/border-e — instead of physical pl/pr/left/right variants. That means every spacing, border, and positioning rule flips automatically when dir changes, without per- component overrides.

Radix primitives (Dialog, Popover, DropdownMenu, Select, Tabs, and the rest) consume the same DirectionProvider, so keyboard navigation, side positioning, and animation origins all follow direction. A physical-properties audit script (audit:direction) runs in CI to prevent regressions where a stray pl-4 sneaks back in.

Known considerations

Directional icons — chevrons, arrows, carets — need per-usage judgment. An accordion chevron should flip in RTL because it points in the reading direction; a play button should not, because it represents physical playback direction. See the icon audit for classifications of the directional icons shipped with the library.

Mixed-direction content is supported via dir="auto" on individual elements — useful for user-generated text that may contain either script. Numbers, dates, and code blocks should stay LTR even inside RTL contexts, which CSS unicode-bidi handles automatically for most layouts.

Components that need extra attention in RTL

Most components flip cleanly. A few expose decisions that belong to the consumer rather than the library:

ComponentWhat to think about
DataTableColumn order follows the columns prop. For semantically ordered data (e.g., chronological), consider reversing column definitions in RTL.
ComboboxSearch and chevron icon placement flips automatically; confirm filter direction matches expected UX.
Calendar / DatePickerWeek start may differ by locale (Sunday vs. Saturday) — that is a locale concern, not a direction concern, but often co-occurs.
PaginationPrev/next buttons swap visually. Ensure any custom arrow iconography also flips.
BreadcrumbSeparator glyph should point in reading direction.
Accordion / CollapsibleChevron rotates in reading direction when expanded.

Test your RTL integration

These docs include a live direction toggle next to the theme toggle in the sidebar (desktop) and header (mobile). Flip it to RTL and navigate through any component page to see how the real components behave under the direction you plan to ship.