Guide to CSS unicode-bidi for Arabic and Hebrew Text
This article provides an overview of the CSS
unicode-bidi property and explains how it controls the
rendering of bidirectional text. It covers how the Unicode Bidirectional
(BiDi) algorithm processes right-to-left (RTL) languages like Arabic and
Hebrew, identifies common visual layout issues when mixing different
text directions, and details how the specific values of
unicode-bidi—used alongside the direction
property—resolve punctuation misplacement and directional bleed.
Understanding the Bidirectional (BiDi) Algorithm
Scripts such as Arabic and Hebrew are written from right to left (RTL), while scripts such as Latin are written from left to right (LTR). When these scripts are mixed in a single sentence or user interface, browsers use the Unicode Bidirectional Algorithm to determine the layout order.
The algorithm assigns strong directional properties to characters:
- Strong RTL characters: Hebrew and Arabic alphabets.
- Strong LTR characters: Latin, Cyrillic, and Greek alphabets.
- Weak and Neutral characters: Numbers, punctuation, spaces, and mathematical symbols.
Neutral characters lack an intrinsic direction; their visual position is inferred from adjacent strong characters. This dynamic causes visual errors when embedding RTL names or snippets into LTR text, or vice versa, often displacing punctuation marks (such as periods, exclamation marks, or parentheses) to the wrong side of the phrase.
The Role of the
unicode-bidi Property
The unicode-bidi property instructs the browser on how
to treat the bidirectional levels inside an element relative to its
surrounding text. It must be paired with the CSS direction
property (direction: rtl; or direction: ltr;)
to have an effect.
Key Values of
unicode-bidi
normal: The default value. The element does not open an additional level of embedding; directionality is determined entirely by the standard BiDi algorithm and the inheriteddirection.embed: Opens an additional level of embedding. The direction specified by thedirectionproperty applies inside the element, but the element still interacts with surrounding inline elements for bidirectional ordering.isolate: Creates a directional boundary around the element. The text inside is calculated independently, preventing its internal directionality from affecting the positioning of adjacent punctuation or words outside the element. This is the CSS equivalent of the HTML<bdi>tag and is the standard approach for dynamic text.bidi-override: Overrides the intrinsic directional properties of all characters inside the element. Characters are rendered strictly according to the specifieddirectionproperty, regardless of whether they are Arabic, Hebrew, or Latin.isolate-override: Combines the behavior ofisolateandbidi-override. It isolates the element from its surroundings while strictly forcing the specified direction on all interior characters.plaintext: Calculates directionality solely based on the first strong directional character found within the element, ignoring the parent container'sdirectionproperty. If the element begins with Arabic or Hebrew, it renders as RTL; if it begins with Latin, it renders as LTR.
Practical Handling of Hebrew and Arabic
Fixing
Punctuation and Spillover with isolate
When displaying a Hebrew or Arabic phrase inside an English paragraph, trailing punctuation often jumps to the beginning of the RTL phrase because the browser considers the punctuation part of the surrounding LTR flow.
.user-name {
direction: rtl;
unicode-bidi: isolate;
}Applying unicode-bidi: isolate ensures that an Arabic
name such as "محمد!" does not let the exclamation mark spill into the
surrounding English sentence structure.
Formatting Codes
and Keys with bidi-override
In cases where numbers, serial codes, or mixed strings must read in a strict sequence regardless of script rules (such as an Arabic product code that must be displayed strictly from left to right):
.serial-number {
direction: ltr;
unicode-bidi: bidi-override;
}This prevents the browser from reversing segments containing Arabic or Hebrew letters within the code.
Dynamic Feeds with
plaintext
In applications with user-generated content where the language is unknown at render time (e.g., chat messages or social feeds):
.message-body {
unicode-bidi: plaintext;
}The browser evaluates the text on a line-by-line basis. If a user posts in Arabic or Hebrew, the container automatically aligns and flows right-to-left without requiring server-side language detection.