ui-ux

Designing Accessible Multi-lingual UI: RTL Layout Systems in CSS

How do you prevent layout breakage when rendering Arabic and English interfaces from the same components? CSS logical properties and a direction-aware layout system.

Engineering question: How do you build one set of components that renders correctly in both Arabic (right-to-left) and English (left-to-right) without maintaining two separate stylesheets — and without the layout breaking when content switches language?

The old approach was to ship a second rtl.css that mirrored every rule. It's a maintenance trap: every new component needs two implementations, and they drift apart. The modern approach is to write direction-agnostic CSS once, and let the browser mirror it.

Stop thinking in left/right; think start/end

Physical properties (margin-left, padding-right, left) are hard-coded to a direction. Logical properties are relative to the text flow, so they flip automatically when dir="rtl" is set.

Physical (don't)Logical (do)
margin-leftmargin-inline-start
padding-rightpadding-inline-end
left: 0inset-inline-start: 0
text-align: lefttext-align: start
border-leftborder-inline-start

Write the component once with logical properties:

CSS
.card {
  padding-inline-start: 1rem; /* "start" = left in LTR, right in RTL */
  border-inline-start: 2px solid var(--accent);
  text-align: start;
}

Then the only thing the app sets per locale is the direction on the root element:

HTML
<html lang="ar" dir="rtl">
  <!-- or lang="en" dir="ltr" -->
</html>

The browser mirrors padding, border, and alignment for you. One stylesheet, both directions.

Flexbox and grid already understand direction

flex-direction: row follows the document direction, so a row of items reverses automatically in RTL — no override needed. The gap, order, and alignment all respect the inline axis. Where you previously reached for justify-content: flex-start, start-based logical values keep doing the right thing in both directions.

The things that must NOT mirror

Mirroring is correct for layout, but a few elements are direction-independent and should be pinned with physical properties on purpose:

  • Numbers, dates, and phone numbers stay LTR even inside RTL text. Wrap them: <span dir="ltr">+20 100 …</span> or use unicode-bidi: isolate.
  • Code blocks and URLs are always LTR.
  • Brand logos and media controls (play/pause) usually shouldn't flip.
  • Icons with directional meaning (a "back" chevron) should flip; decorative icons shouldn't. Decide per icon.

Don't forget the typography

RTL isn't only layout. Arabic needs a font with proper Arabic glyph coverage and tends to read better with slightly increased line-height, since Arabic letterforms are taller and more connected than Latin. Set the Arabic font stack on the lang="ar" scope so each language gets type tuned for it.

The result

By building on logical properties, flow-relative flexbox, and a single dir switch at the root — with deliberate exceptions for numbers, code, and logos — you get one component library that renders cleanly in both languages. New components are written once and work in both directions by default, which is the only way a bilingual product stays maintainable as it grows.

LET’S BUILD SOMETHING USEFUL

Your challenge could be our next success story.

Tell us what you’re working on and what’s getting in the way. We’ll help you find the right next step.

Start a Project