The RTL guide to UI elements
When a page flips right-to-left, not everything flips with it. The hard part is not switching on dir="rtl". It is knowing what should mirror, what looks broken the moment you mirror it, and which logical CSS property removes the problem at the root instead of making you write two rules for every component. This is that reference, in one place.
From physical to logical properties
Most broken Arabic layouts trace back to a single property written as a side instead of a direction. This table is the direct substitution: write the middle column, and stop needing a separate rule per direction.
| Do not write | Write this instead | Why |
|---|---|---|
margin-left / margin-right | margin-inline-start / margin-inline-end | The single biggest cause of a broken Arabic layout. One rule then serves both directions. |
padding-left / padding-right | padding-inline-start / padding-inline-end | Inner spacing for buttons and fields that carry an icon on one side. |
left / right | inset-inline-start / inset-inline-end | Positions of floating things: toasts, floating buttons, popovers. |
text-align: left / right | text-align: start / end | Lets text follow the content direction instead of being pinned to one side. |
border-left / border-right | border-inline-start / border-inline-end | The coloured edge on alerts and blockquotes. It moves to the correct side on its own. |
border-radius: a b c d | border-start-start-radius … | Matters for joined buttons and input groups, where only the outer corners are rounded. |
transform: translateX(100%) | translateX(calc(100% * var(--dir))) | Transforms have no logical equivalent, so define a direction variable and multiply by it. |
transform-origin: left | transform-origin: inline-start | Progress bars and toast timers that drain along the reading direction. |
float: left | float: inline-start | Images wrapped by text inside articles. |
background-position: left | background-position-x + [dir] | No logical equivalent, so you need an explicit rule inside [dir="rtl"]. |
What mirrors, and what must never mirror
Flipping every icon with scaleX(-1) is a common mistake that produces an uncanny interface: a backwards clock, a backwards camera. The rule: mirror anything that indicates reading order or sequence, and leave anything that depicts a physical object or follows a global convention.
Mirrors
- Directional arrows: next and previous, back, undo, and "see more".
- Alignment and indent icons, and list icons that show text lines.
- Progress bars and sliders, which start from the right.
- Button order in a dialog footer.
- Skeleton shimmer direction and slide-in animations.
Never mirrors
- Clocks, timers, and anything showing hands. Time does not mirror.
- The loading spinner, whose rotation is not a reading direction.
- Status icons: check, error, warning, info.
- Icons of real objects: keys, locks, cameras, shopping carts.
- Logos, and any icon containing a Latin letter or a digit.
- Media play buttons ▶, a global convention that ignores language direction.
- The downward chevron on a dropdown, which is vertical, not horizontal.
Bidirectional text (Bidi)
The hardest Arabic bugs are not layout bugs. They live in the single line that mixes Arabic, Latin and digits. The browser's bidi algorithm runs automatically, and in a handful of recurring cases it gets the result wrong.
Numbers and IDs inside Arabic text
Numbers run left-to-right even inside an Arabic sentence. Trouble starts when they sit next to #, %, + or -, which can jump to the wrong end. Wrap them in <bdi> or a span with unicode-bidi: isolate.
Code identifiers inside an Arabic sentence
A token like aria-expanded or max-width: 100% at the end of an Arabic sentence can have its hyphen or colon displaced. Any Latin run inside Arabic text must be direction-isolated.
User-generated content
Never assume the language of a comment or a filename typed by a user. Put dir="auto" on the input and on the place it is displayed, and let the browser decide from the first strongly-directional character.
Fonts and line height
Arabic letterforms are taller and more connected than Latin ones, so a line height tuned on English feels cramped in Arabic. Raise line-height by roughly 0.15 to 0.25 for Arabic text, and drop letter-spacing entirely, because it breaks the joins between letters.
RTL notes per element
219Every element page in the dictionary carries its own RTL section. This is a fast index of every note published so far.
- Swipe Actionsإجراءات السحبLeading and trailing swap · Raw deltas stay physical · Where the panel anchors · The action icons · Clashing with the back gesture5
- Floating Action Buttonزرّ الإجراء العائمThe corner moves to the opposite side · The button glyph does not mirror · The icon at the start of the extended pill · The cluster axis does not flip · The fan-out origin flips by hand5
- Pull to Refreshالسحب للتحديثThe gesture does not mirror · The indicator rotation · Indicator text and the timestamp · A horizontal swipe on the same list · Insets around the indicator5
- Action Sheetورقة الإجراءاتThe rows have nothing to mirror · The leading icon · The destructive row keeps its colour and its slot · The popover anchor on iPad · The Arabic name is a different length5
- Infinite Scrollالتمرير اللانهائيWhich axis actually flips · The spinner and the skeleton rows · The item counter · The horizontal carousel · The direction of incoming text5
- Scrollspyمتتبّع التمريرWhich side the column sits on · The active indicator bar · Indenting nested levels · The observer does not mirror · The reading progress bar5
- Truncation (Ellipsis and Line Clamp)قصّ النصّWhich edge gets cut · The fade mask · A middle cut counts in logical order · A Latin name inside an Arabic line · Line height in a clamped paragraph5
- Segmented Controlالشريط المقسّمSegment order · Moving the indicator · The end corners · The arrow keys · Latin labels5
- Carouselالشريط الدوّارThe inline axis reverses by itself · The arrows: place, glyph, and job · The sign of scrollLeft · What CSS will not flip for you · The artwork stays as drawn5
- Popoverاللوحة المنبثقةPlacement keywords: logical vs physical · The arrow offset · A portalled panel loses dir · Flipping at the viewport edge · The block axis does not mirror5
- Command Paletteلوحة الأوامرIsolating the command label · The shortcut hint inside a row · The direction of the command field · The highlighted row indicator · The shortcut on an Arabic layout5
- Menu (Dropdown Menu and Context Menu)قائمة الأوامرWhich side the submenu opens on · The submenu arrow · The mark column and the shortcut column · The shortcut text itself · ArrowRight and ArrowLeft5
- Site Header and Navbarترويسة الموقع وشريط التنقّلOrder across the strip · The list keeps its own padding · A dropdown under a nav item · The language switcher · The toggle and its panel5
- Sidebarالشريط الجانبيWhich edge it sits on · The border against the content · Indenting nested items · The chevron and the hamburger · The collapse animation5
- Dividerالخطّ الفاصلThe inset rule · The labelled divider · The vertical rule between controls · The fading gradient · The draggable splitter5
- CardالبطاقةThe horizontal card · Padding and corner radius · The action row · The corner badge · The image itself5
- Data Tableجدول البياناتColumn order · The frozen column · The sort arrow · Numeric columns · Horizontal scrolling5
- Avatar and Avatar Groupالصورة الرمزية ومجموعتهاWhich way the row overlaps · Stacking order · The status dot corner · The counter and its plus sign · What never mirrors: photo and initials5
- AlertالتنبيهThe coloured edge · The icon and dismiss row · Status icons never mirror · Latin runs inside the message · A banner portaled out of the tree5
- BadgeالشارةWhich corner it takes · The plus sign in the cap · Which digits you ship · The dot and its offset · A badge after a text label5
- Progress Bar vs Spinner vs Ringمؤشّر التقدّمWhich way the bar fills · The indeterminate sweep · The spinner rotation · Ring geometry against its label · Numerals and numbering system5
- File Upload / Dropzoneرفع الملفاتThe file row · The per-file bar · A Latin file name in an Arabic row · Size and the numeral system · The system dialog5
- Combobox / Autocompleteحقل الإكمال التلقائيPopup alignment and the top layer · The loading spinner · Highlighting inside a word · An Arabic query over Latin labels · The caret and its keys5
- Text Inputحقل النصWhich side the adornments sit on · A Latin value inside an Arabic form · dir="auto" as the default · The order inside the counter · Arabic-Indic digits in the value5
- SliderالمنزلقThe whole axis reverses · Anchoring the fill and the thumb · The arrow keys swap meaning · The pointer maths · The number itself does not flip5
- Radio Groupمجموعة أزرار الاختيارWhat the left and right arrows mean · Where the circle sits · How a horizontal group wraps · The travelling indicator · What stays in DOM order5
- Checkboxمربّع الاختيارWhere the box sits · The check and the dash · Indenting a nested tree · The focus ring · The select column in a table5
- Form Fieldحقل النموذجWhere the label and the asterisk sit · The direction of the value itself · The status icon inside the box · Isolating a Latin value inside the message · The native browser message5
- Bottom Sheetالورقة السفليةThe grabber does not mirror · The header action row · Safe-area insets are physical · The vertical drag is direction-neutral · What is inside the sheet5
- Tab Bar / Bottom Navigationشريط التنقّل السفليThe destination order flips · The indicator travels the logical axis · The badge: its corner and its number · Object icons never mirror · The safe area is the exception to the logical rule5
- Drawer / Side Panelالدرج الجانبيThe anchor edge itself flips · The slide needs a direction variable · The swipe-to-close direction reverses · The close button and the shadow · What does not mirror: block axis and blocking5
- Empty Stateالحالة الفارغةOnly directional artwork mirrors · An illustration with Latin text is replaced, not flipped · The centred block and the echoed query · The action row · The empty state inside a table5
- Chip / TagالشريحةThe icon and the × inside the chip · How the row wraps and aligns · Arrow keys inside the group · The scrollable chip rail · A Latin value inside an Arabic chip5
- Switch / Toggleمفتاح التبديلWhich way the thumb travels · How the track fills · Where the label sits · The glyphs inside the track · The drag gesture5
- Paginationترقيم الصفحاتThe order of the numbers · The prev and next chevrons · Numerals and the character between them · The arrow keys · Carousel dots and scrolling5
- Modal Dialogالنافذة الحواريةFooter button order · The close button corner · The scrim does not mirror · The portal escapes the direction · Scroll lock and scrollbar compensation5
- Dropdown / Selectالقائمة المنسدلةPopup alignment · The chevron does not mirror · Inside the option row · Vertical keys · Arrows in a horizontal list5
- TooltipالتلميحSide, alignment, and edge collision · The arrow offset · Direction of the tooltip text · The enter-animation origin · The native title attribute5
- TabsالتبويباتThe arrow keys swap · The active underline · Scrolling an overflowing strip · The scroll-shadow gradients · What must never flip5
- Steps / Stepperمؤشّر الخطواتSequence direction · How the connector fills · The numerals in the circles · The checkmark never mirrors · The vertical stepper on mobile5
- Skeletonهيكل التحميلPath of the sweep · Tilt of the gradient · The geometry of the blocks · The short last line · Skeleton padding must equal component padding5
- Accordionالأقسام المطويةWhere the indicator sits · A chevron that rotates · A sideways indicator · Indentation and padding · The navigation keys5
- Toastالإشعار العائمWhere the toast sits · Entry animation · The timer bar · The undo icon · Display duration5
- Breadcrumbsمسار التنقّلTrail direction · The chevron separator · Latin names inside an Arabic trail · Collapsing and truncation4