Skip to main content

Right to left

Every part of the system works in Arabic (right to left) as well as English, from the start. Set the language and direction on <html>:

HTML
<html lang="ar" dir="rtl">

lang chooses the fonts and Arabic adjustments (:lang(ar)); dir chooses the direction. Set both. A page can contain the other language in a block with its own lang and dir.

1. Logical properties only​

The CSS never says left or right. It says start and end, which follow dir:

Instead ofWrite
margin-left, padding-rightmargin-inline-start, padding-inline-end
left: 0, right: 0inset-inline-start: 0, inset-inline-end: 0
border-leftborder-inline-start
text-align: lefttext-align: start
width, heightinline-size, block-size (where it describes the text axis)
float: leftflex or grid with justify-content: start

Flex and grid already follow dir: a row starts on the right in Arabic.

2. What mirrors, and what doesn't​

Mirrors with dirNever mirrors
Layout: sidebar side, page head, table columnsThe logo and wordmark
Chevrons, arrows, "back" and "forward"The pattern (a fixed geometric figure)
Undo, retry, external-link iconsCheck marks, clocks, calendars, search, play/pause
Progress bars, the split bar, the bullet chart (grow from the start)Numbers and the digits within them
The order of chart categories and time on a column chartA chart's value axis (up is more in every script)
A disclosure's chevron (points the way text reads)Media timelines, code, maths
The pattern's fade (it clears behind the start side, where text begins)Phone numbers, codes, URLs

Icons that mirror get .al-mirror: .al-mirror:dir(rtl) { transform: scaleX(-1) }. The system's direction rules use :dir(rtl), not [dir="rtl"] .x, so they follow the nearest direction: a dir="ltr" block inside an Arabic page (a code sample, an English quote) doesn't mirror. Likewise a lang="en" element inside an Arabic page gets Latin type metrics back (size, line height, tracking).

The wordmark doesn't mirror; in Arabic pages it's written in Arabic, "معامل آرابيسك" (lang="ar", untracked), beside the same mark.

3. Bidi isolation​

A left-to-right run (a number with its currency, a code, an English name, an email address) inside Arabic text must be isolated, or punctuation and symbols around it drift to the wrong side.

InUse
Markup<bdi>£108,000</bdi>, or class="al-ltr" for content that's always LTR (codes, emails)
A string (an aria-label, a tooltip, a translated sentence)U+2066 (LRI) … U+2069 (PDI) around the run
User content of unknown directiondir="auto" on the element, or .al-auto-dir
An input for an LTR value (email, URL, a tax code)dir="ltr" on the input; its label stays in the page's direction

Examples:

HTML
<p>يدفع العرض <bdi>£108,000</bdi> سنويًا.</p>
<p>الرمز <bdi>0T</bdi> يُخضع أجرك كله للضريبة.</p>
JavaScript
const text = `راتب ⁦${formatMoney(108000, "GBP", { lang: "ar" })}⁩، ومكافأة 15%`;

Without isolation, "راتب £108,000،" can render with the pound sign after the number; with Arabic-Indic digits ("£١٠٨٬٠٠٠") the drift is worse, since those digits don't carry the currency sign with them as Western digits do.

4. Digits​

Arabic can be written with Western digits (123) or Arabic-Indic digits (١٢٣). Both are correct; it's the reader's preference, so offer it as a setting and default to Western, which is what most Arabic finance and tech products use. js/format.js:

JavaScript
import { formatNumber, formatMoney, formatPercent, parseNumber } from "./js/format.js";
formatMoney(6010, "GBP", { lang: "ar", numerals: "arab" }); // "£٦٬٠١٠"
formatPercent(0.62, { lang: "ar", numerals: "arab" }); // "٦٢٪؜"
parseNumber("١٠٨٬٠٠٠"); // 108000
  • Accept either in inputs: parseNumber reads both digit sets, Arabic separators (٬ ٫) and "108k".
  • Money writes its short symbol first in both languages (£6,010), as one isolated run, because Arabic locales otherwise spell some symbols out ("UK£") and move them.
  • Use inputmode="decimal" on number inputs so phones show the right keypad.
  • Dates are written day, month, year in both languages; in Arabic the day is at the right. js/datepicker.js writes them in the chosen digits (formatDate), reads either (parseDate), and its calendar runs from the right with the week from Saturday. Don't use <input type="date"> on an Arabic page: its calendar follows the browser's language, not the page's.

5. Type​

See typography. In short: larger (×1.08), more leading, no letter-spacing, no uppercase or italic, Arabic punctuation (، ؛ ؟).

6. Testing​

Check every screen in all four combinations (light and dark, English and Arabic). In Arabic, look for:

  • the layout mirrored (sidebar on the right, actions at the left end);
  • letters joined (any letter-spacing breaks them);
  • numbers, amounts and codes whole, with symbols on the right side;
  • chevrons pointing the way text reads;
  • nothing clipped by the larger size and leading.