Designing for Right-to-Left Is Not Flipping the Layout
What actually changes when an interface runs in Arabic — which things mirror, which must not, and the CSS that makes one stylesheet serve both directions.
Noch nicht übersetzt
Diese Seite liegt noch nicht auf Deutsch vor. Sie lesen die englische Fassung.
EnglishThe usual first attempt at right-to-left support is direction: rtl on the
root element, a look at the result, and a conclusion that it mostly works.
It mostly does. The remaining ten percent is where the interface stops feeling translated and starts feeling wrong to the people reading it.
The mental model
RTL is not a mirror applied to a page. It is a change to the inline direction — the axis text advances along. Everything that follows reading order flips with it. Everything that does not, must not.
Getting this right is mostly a matter of sorting your interface into three buckets.
Mirrors
- Text alignment, and the order of items in a row
- Navigation, breadcrumbs, and the direction of "next" and "back"
- Progress bars, sliders, and carousels
- Drawers and panels docked to a side
- Table column order
- Indentation, list markers, and tree hierarchies
- Directional arrows and chevrons
Does not mirror
- Clocks. Time still runs clockwise.
- Media controls. Play, fast-forward and rewind point the same way; they refer to a timeline, not to reading order.
- Numbers.
2026is written left to right inside Arabic text. - Latin text and code. A code sample stays LTR wherever it appears.
- Phone numbers, URLs, email addresses.
- Logos and brand marks, unless the brand has an RTL variant.
- Checkmarks, and most non-directional iconography.
Depends
- Charts. A time axis usually still runs left to right, because that convention is stronger than reading direction in data visualisation. A ranked bar chart, on the other hand, should start on the inline-start edge.
- Icons carrying letterforms. An icon containing a Latin glyph should not be mirrored into an unreadable one.
The CSS that does the work
Modern CSS handles nearly all of this if you stop naming physical sides.
Every property below has a logical counterpart, and using it means one
stylesheet serves both directions with no [dir="rtl"] overrides at all:
| Physical | Logical |
|---|---|
margin-left / margin-right | margin-inline-start / margin-inline-end |
padding-left / padding-right | padding-inline-start / padding-inline-end |
left / right | inset-inline-start / inset-inline-end |
text-align: left | text-align: start |
border-left | border-inline-start |
width / height | inline-size / block-size |
In Tailwind these are the ms-, me-, ps-, pe-, start-, end- and
text-start utilities. Adopting them is the single highest-leverage change you
can make; most RTL bugs are a pl-4 that should have been ps-4.
Arrows
Directional icons need to flip, and doing it once beats branching at every call site:
[dir="rtl"] .icon-directional {
transform: scaleX(-1);
}Build that into the icon component rather than the pages that use it. Then "forward" is correct everywhere by construction.
Keep code and numbers upright
Bidirectional text is where things get genuinely subtle. A Latin identifier inside an Arabic sentence can be reordered by the bidi algorithm in ways that change what the reader sees:
code,
pre,
.ltr-content {
direction: ltr;
unicode-bidi: isolate;
}isolate is the important half. It tells the bidi algorithm to treat the
element's contents as a self-contained run, so a trailing bracket or full stop
cannot jump to the other end of the line.
What logical properties will not fix
Three things still need thought.
Shadows and gradients. box-shadow: 4px 4px is directional and has no
logical form. A shadow implying a light source from the inline-start edge needs
to be flipped by hand, or — simpler — made symmetrical.
Animations. A panel that slides in from the right must slide in from the left in RTL. CSS transforms take no logical values, so drive the offset through a custom property that changes with direction:
.drawer {
--slide-from: 100%;
animation: slide-in 240ms ease-out;
}
[dir="rtl"] .drawer {
--slide-from: -100%;
}
@keyframes slide-in {
from {
translate: var(--slide-from) 0;
}
to {
translate: 0 0;
}
}Typography. Arabic needs more vertical breathing room than Latin at the
same nominal size. Its letterforms have taller ascenders and deeper descenders,
and diacritics sit outside the x-height. A line height that looks generous in
English will look cramped in Arabic. Arabic also has no uppercase, so
text-transform: uppercase and letter-spaced small caps — a staple of eyebrow
labels — simply do nothing, and any design leaning on them for hierarchy loses
that hierarchy entirely.
Pick a font with real Arabic coverage while you are at it. Falling back to whatever the system provides means the RTL build has a texture nobody chose.
Testing it
Three checks catch most of what is left:
- Read it in Arabic, not in a reversed English placeholder. Pseudo-RTL catches layout bugs but hides typographic ones.
- Tab through the page. Focus order follows the DOM, not the visual layout — if they disagree in RTL, the DOM order is wrong.
- Look for horizontal overflow at 320px. Fixed widths and physical positioning tend to fail in the same places, and RTL surfaces them.
None of this is expensive if it is done from the start. It is expensive if it
is done after two hundred components have hard-coded padding-left.