Skip to content

Right-to-left done right: lessons from an Arabic-first site

Logical CSS, mirrored arrows, Latin digits and fonts without Arabic letters: the details that make an Arabic interface feel native instead of flipped.

Dahmane Abdelmalek

Oct 23, 20263 min readPart 2 of 3

Most of my client work is for Arabic speakers, and I've seen what usually happens to the Arabic versions of websites: the English layout, flipped at the last minute, with arrows pointing the wrong way and numbers that read backwards.

On this site, Arabic was part of the design from the first day. Here are the details that made the difference.

Think in start and end, not left and right

Setting dir="rtl" on the page reverses the text, but every margin-left and left: 0 in the stylesheet stays exactly where it was. The fix is to stop writing left and right altogether.

CSS logical properties describe the start and the end of a line instead, and Tailwind has them for everything: ps- and pe- for padding, ms- and me- for margins, border-s, inset-s, text-start. The timeline's date column, the blue bullets in this article, the dividers between figures and the slide-in menu all use them. In Arabic they all move to the right, with no extra CSS.

styles/app.css
@utility square-bullets {
  & ul > li {
    @apply relative ps-5;
  }
  & ul > li::before {
    content: '';
    @apply absolute inset-s-0 top-[0.7em] size-1.5 bg-primary;
  }
}

Mirror what points, not what shows

Arrows that mean "next" or "back" must point the other way in Arabic. A logo, a play button or a check mark must not. So only directional icons flip, and only on right-to-left pages:

components/content/arrow-link.tsx
<ArrowRightIcon aria-hidden className="size-4 rtl:rotate-180" />

The diagonal "opens elsewhere" arrow is flipped horizontally instead, with rtl:-scale-x-100, so it keeps pointing up.

Keep numbers left to right

Arabic runs right to left, but numbers inside it still read left to right. That holds for a single number and breaks for a range: "15–25%" can come out as "25%–15". Two rules fix it:

  • Figures that mix digits and symbols get their own direction: <span dir="ltr">15–25%</span>.
  • Dates and durations use Latin digits, the norm in Algeria and across North Africa, so they match the numbers typed in the CMS.
lib/i18n/format.ts
// Arabic uses Latin digits to match the CMS content ("19/20", "15–25%").
const INTL_LOCALES: Record<Language, string> = {
  en: 'en',
  ar: 'ar-u-nu-latn',
  fr: 'fr',
}

Check what your fonts actually contain

IBM Plex has an excellent Arabic font, IBM Plex Sans Arabic. IBM Plex Mono, the monospaced font for labels and code, has no Arabic letters at all. Every Arabic word in a monospaced label fell back to a system font, with letters that didn't join.

The fix is one line in the font stack: Plex Mono for Latin text, then Plex Sans Arabic for anything Plex Mono can't draw.

styles/app.css
@theme {
  /* Plex Mono has no Arabic letters; without Plex Sans Arabic next, browsers
     fall back to a system monospace font that renders Arabic disconnected. */
  --font-mono:
    'IBM Plex Mono', 'IBM Plex Sans Arabic', ui-monospace, SFMono-Regular,
    Menlo, Consolas, monospace;
}

The small things

  • Arabic needs more room between lines than Latin text; Arabic pages use a line height of 1.75.
  • Lists joined in code use the Arabic comma "،" instead of ",".
  • Initials, like the ones shown for a project without a screenshot, are separated by an invisible zero-width non-joiner. Without it, two Arabic letters join into what reads like a word.

Test it like a visitor would

None of this shows up in a code review. Every page on this site is checked in Arabic in a real browser, at phone width too: does the menu slide in from the left, do the arrows point the right way, does anything overflow? It takes longer than checking the English page, and it's the only way an Arabic visitor gets a site that feels made for them.

Part 3 goes behind the content itself: how Markdown and code from the CMS become safe, highlighted HTML on the server.

Newsletter

Get new articles by email

One email per new article. Unsubscribe anytime.

Prefer a feed reader? RSS feed

Responses

Never shown on the site.

Responses appear once they are approved.

Contact

Have a project in mind?
Let's build it.

Open to remote roles and freelance projects.