Foundations
Arabic and RTL principles
Logical properties, deliberate mirroring, native Arabic type, numerals, isolated left-to-right runs, inputs and portals: the decisions every component makes for you.
Flipping a layout from left-to-right to right-to-left is the easy part, and most kits now do it. An Arabic product still breaks in the places a mirror cannot reach: the font, the line height, the order of digits inside a sentence, the direction of a phone field, the language a screen reader is told. Every Ritla UI component is built against the same checks Ritla runs on live sites, so these are decided once, in the component, instead of on every screen.
This page is the short version of those decisions. Each section names the checks that catch the mistake when it ships anyway.
Logical properties, never physical ones#
A layout written in physical directions has to be written twice: once for English and once, overridden, for Arabic. A layout written in logical directions is written once and follows dir.
| Physical (a bug) | Logical (what we ship) | CSS behind it |
|---|---|---|
ml-4, mr-4 | ms-4, me-4 | margin-inline-start, margin-inline-end |
pl-4, pr-4 | ps-4, pe-4 | padding-inline-start, padding-inline-end |
left-0, right-0 | start-0, end-0 | inset-inline-start, inset-inline-end |
text-left, text-right | text-start, text-end | text-align: start, text-align: end |
border-l, border-r | border-s, border-e | border-inline-start, border-inline-end |
rounded-l-8 | rounded-s-8 | border-start-start-radius, border-end-start-radius |
Components contain no physical direction class at all, and the Kanz build fails on one. In your own code, the same mistakes show up as R030, R031, R032 and R033. Do not fake a right-to-left row with flex-direction: row-reverse either: the screen mirrors, the tab order does not (R081).
Mirror deliberately#
Mirroring is a decision per element, not a transform on the page.
Mirrors: arrows, chevrons, back and next buttons, navigation, progress bars, sliders, steppers, breadcrumbs, anything that points along the reading direction.
Never mirrors: media controls (play, pause, seek), clocks and timers, checkmarks, logos, the numeric axis of a chart, phone numbers, card numbers, code.
Directional icons in Ritla UI mirror on their own through the icon helper, from a list kept in step with the Figma file, so nobody adds a flip by hand to the wrong icon. An arrow pointing against the direction its control moves is R025. Copy that says "click the arrow on the right" is wrong in one of the two languages (R082).
Native Arabic type#
- An Arabic font, always. Latin runs use Geist, Arabic runs use IBM Plex Sans Arabic, and every font stack contains the Arabic family, so Arabic never falls back to a system font that happens to have the glyphs (
R050). - Taller lines. Arabic needs more room above and below than Latin. Arabic body text gets a line height of at least 1.5 (
R052). - No letter-spacing. Arabic is a connected script. Tracking breaks the joins, so Arabic text is never letter-spaced (
R051), and the uppercase-and-tracked label style that suits English is not applied to Arabic (R055). - No italics, no tiny text. Arabic has no true italic (
R054), and its detail collapses below 14px (R053).
Switching the language switches the font family, the line heights and the tracking through the theme's variables. Components never carry a dark: or rtl: variant for type.
Numerals#
Arabic interfaces use two digit systems. Both are correct, and mixing them on one screen is not (R061).
- Western digits:
0123456789 - Arabic-Indic digits:
٠١٢٣٤٥٦٧٨٩
Ritla UI defaults to Western digits and switches to Arabic-Indic through one numerals setting on the provider. Numbers are formatted with Intl.NumberFormat and the -u-nu- extension rather than by replacing characters, so grouping and decimal separators follow the same choice. Dates follow it too: an English month name or an MM/DD/YYYY date inside Arabic text is R060. Percent signs and units keep a consistent order (R063).
Isolate left-to-right runs#
The Unicode bidi algorithm reorders neutral characters around the strong ones next to them. Inside an Arabic sentence, a phone number, an email address, a product name or an order number can come out in the wrong order, with its punctuation on the wrong side (R021, R024).
- Phone numbers, card numbers, one-time codes, IDs and code go in a left-to-right isolate:
<bdi dir="ltr">orunicode-bidi: isolatewithdir="ltr". - Brand and product names embedded in Arabic text go in
<bdi>. - Text that can arrive in either language (user content, server messages, search fields) gets
dir="auto", so an English message inside an Arabic layout keeps its full stop at the end. - An intentional English run inside Arabic carries
lang="en", so screen readers switch voice and the font stack switches family (R080).
The Mirrored preview mode on every component page exists to catch this class of bug: it is the English content laid out right to left, which separates a direction bug from a translation one.
Inputs#
- Text fields follow the page direction, and the caret and placeholder sit on the start side, even while the field is empty (
R023). - Fields whose content is left-to-right by nature stay left-to-right inside an Arabic form:
tel,email,url, card numbers, one-time codes (R070). - A
<select>with Arabic options renders right to left (R072). - Labels, help text and validation messages are translated, not just the placeholder (
R071,R012), and identity fields keep theirautocompletetokens (R073).
Portals and overlays#
Dialogs, drawers, popovers, menus, tooltips and toasts render outside the element that opened them, usually at the end of <body>. If the page is Arabic but a section is English, or the other way round, a portal that reads direction from the document gets it wrong.
Ritla UI overlays read the nearest dir and lang of the element that opened them and set both on the overlay, so a menu opened from an English card inside an Arabic page is English, and keyboard arrows move the right way in both.
The document itself#
Most of the above fails silently if the page does not declare what it is. Set dir and lang on <html>, not on a wrapper <div> (R001, R002), give every Arabic page its hreflang pair (R003), a canonical URL in its own language (R006), and an Arabic title, description and og:locale (R004, R005).
Check your own pages#
Every rule linked on this page is a check Ritla runs. Scan your site to see which of them your pages fail, or read the full list of checks.