Direction and RTL
One attribute on the html element. Everything that should flip does, and the things that must not are already held down.
One attribute
<html lang="ar" dir="rtl">That is the whole switch. The components use logical properties throughout, so padding, margins, borders and rounding follow the reading direction rather than the screen. The sidebar moves to the right, menus open the other way, and chevrons that mean “forward” point the other way.
What does not flip, and must not
- Numbers. Digits read left to right in every direction. A phone number, a price and a version stay as they are.
- Code. Every code block and inline snippet is forced back to
ltr. Mirrored code is unreadable and would be wrong if copied. - Charts. A time axis runs in its own direction. Flipping it would reverse the meaning of a trend, which is worse than looking foreign.
- Media controls and progress. Play still points at the playhead and a bar still fills toward completion.
Writing components that survive the switch
Use logical properties, never physical ones. This is the entire rule, and there is a guard on it: pnpm check:direction fails on a physical property in component source, so RTL cannot rot quietly between releases.
| Instead of | Write |
|---|---|
| ml-4 mr-4 | ms-4 me-4 |
| pl-4 pr-4 | ps-4 pe-4 |
| border-l border-r | border-s border-e |
| left-0 right-0 | start-0 end-0 |
| text-left text-right | text-start text-end |
| rounded-l rounded-r | rounded-s rounded-e |
When it did not work
One component still sits on the wrong side
Cause: a physical property survived in your own code. Fix: swap it for the logical one above. Verify: pnpm check:direction if you kept the guard, or set dir="rtl" and look.
An icon points the wrong way
Cause: a directional glyph rendered as decoration. Fix: rtl:rotate-180 on chevrons and arrows that mean direction, and nothing on the ones that mean an object.