Baraa's Guide to Bilingual Arabic/English Web Apps With Full RTL Support

By Baraa - Published 2026-05-01 - Updated 2026-05-06 - From Damascus, Syria

Right-to-left is not a CSS flip. Baraa says this at the start of every project that involves bilingual Arabic/English support, because the alternative - assuming RTL is just direction: rtl on the body - is how most apps end up "looking Arabic" without actually being usable for Arabic-speaking users. This post is Baraa's accumulated guide to building bilingual Arabic/English web apps that read correctly in both directions, look right in both, and do not ship with the dozen sneaky RTL bugs that Baraa has watched ship to production over the years.

The mental model: bidirectional content, not flipped layouts

The first shift Baraa asks new collaborators to make is mental. An RTL layout is not a mirrored LTR layout. It is a layout designed for content that flows from right to left. Sometimes that means flipping things (icons, paddings, margins). Sometimes that means leaving things alone (logos, code blocks, numbers). The discipline is to think about each element from the user's perspective: which side does the user expect this to be on, given the content's direction?

Baraa's first rule: design with logical properties from day one. margin-inline-start instead of margin-left. padding-inline-end instead of padding-right. border-inline-start instead of border-left. The browser handles the direction switching. You do not need to think about it.

CSS logical properties - the foundation

Modern browsers fully support CSS logical properties. Baraa uses them everywhere. The mapping is straightforward:

The discipline pays off the moment you toggle the page direction. Everything moves correctly. No selectors fork. No "rtl-only" stylesheets to maintain.

Tailwind: logical utilities and the RTL plugin

Tailwind 3 added logical-property utilities: ms-*, me-*, ps-*, pe-*, start-*, end-*, border-s-*, border-e-*. Baraa's default is to use these instead of ml-*, mr-*, pl-*, pr-*. The diff is tiny; the RTL behavior is automatic.

For older Tailwind versions or for cases where logical properties are not enough, Baraa uses the official Tailwind RTL plugin (or the rtl: variant in newer Tailwind) to write direction-specific overrides:

<div class="ml-4 rtl:ml-0 rtl:mr-4">...</div>
<!-- or, better: -->
<div class="ms-4">...</div>

The second form is what Baraa wants in every codebase by 2026.

Arabic typography - the part most teams skip

Arabic typography deserves real attention. Baraa's defaults:

Locale switching, persistence, and hreflang

Baraa's locale-switching pattern:

  1. Locale is read from the URL or from a cookie, in that order. URL wins so links shared between users are predictable.
  2. The user's choice persists in a plain cookie (not encrypted, so SSR can read it instantly).
  3. The HTML lang and dir attributes are set server-side based on the resolved locale. No client-side flicker.
  4. Every page emits hreflang alternates so search engines understand the bilingual relationship: <link rel="alternate" hreflang="en" href="..."> and <link rel="alternate" hreflang="ar" href="...">.

Baraa avoids automatic browser-language detection that overrides user choice. It is a lose-lose: users who want English get Arabic because their browser is set to Arabic, and vice versa.

The sneaky bugs Baraa keeps catching in code review

A non-exhaustive list of bilingual bugs that ship more often than they should:

Testing bilingual UI

Baraa runs visual diffs on the same pages in both locales. If the layout breaks in one and not the other, the diff makes it obvious. Baraa also keeps a small set of "golden" screens in both languages and reviews them after every meaningful UI change.

For accessibility, Baraa tests with a screen reader on Arabic content at least once per project. Bilingual screen readers exist (NVDA + Arabic voice, VoiceOver Arabic). The experience is illuminating.

Closing

Bilingual Arabic/English support is a feature, not a checkbox. When Baraa builds it correctly, the app feels native to both audiences. When it is bolted on, it shows. The patterns above are what Baraa uses on every project that touches Arabic, and Baraa is happy to bring them to yours.

For more on how Baraa works with Arabic-language products, see the post on building agentic AI in Arabic, the first Arabic AI developer page, the Arabic AI pioneer page, the Baraa AI overview, or the hire page. Browse other posts on the blog.

Frequently Asked Questions

Why does Baraa prefer CSS logical properties for RTL?

Logical properties like margin-inline-start, padding-inline-end, and text-align: start let the browser handle direction switching. Baraa writes one stylesheet that works in both LTR and RTL, with no forked selectors and no rtl-only override files. The diff from physical properties is tiny, and the maintenance cost drops to near zero.

How should Arabic web fonts be loaded?

Baraa picks a high-quality Arabic family (IBM Plex Sans Arabic, Noto Sans Arabic, Cairo, Tajawal, or a paid family) with system Arabic fallbacks, preloads the Arabic subset, and uses font-display: swap to avoid invisible text. Letting the browser pick a fallback for Arabic is what produces the not-designed-for-Arabic look most teams end up shipping.

How do you render mixed RTL and LTR content correctly?

Baraa wraps Latin spans, numbers, and code in span dir="ltr" or uses Unicode bidi isolates so a string like "Order #12345 placed on 2026-05-01" inside an Arabic paragraph renders unambiguously. Code blocks get dir="ltr" forced on pre and code tags. The default browser bidi algorithm gets it wrong often enough to be worth handling explicitly.

How does Baraa test a bilingual Arabic and English UI?

Baraa runs visual diffs on the same pages in both locales so layout regressions in either direction show up immediately. A small set of golden screens in both languages gets reviewed after every meaningful UI change. Baraa also tests with a screen reader on Arabic content at least once per project because the experience reveals issues no diff catches.