Reference

Text direction for mixed Hebrew and English

Put dir="auto" on every paragraph and never on the document. That one line handles almost every document that mixes Hebrew or Arabic with English, and the rest of this page is the handful of cases where it isn't enough.

Direction is a property of a paragraph, not of a file. Everything below follows from that.

The one mistake

Setting direction on the document

A file gets dir="rtl" because it is "a Hebrew document", and every English paragraph in it inherits that. The words stay in order — bidi handles those — but the paragraph aligns to the right and its full stop moves to the left of the sentence.

Inherited dir="rtl"

The migration turned out simpler than expected.

Resolved per paragraph

The migration turned out simpler than expected.

The same happens in reverse: one Hebrew line inside an English document ends up left-aligned with its final period stranded on the right. Neither is a rendering bug. The browser was told the direction and believed it.

How it resolves

The first strong character decides

dir="auto" reads forward through the paragraph until it meets a character with a direction of its own, and takes that direction. Most characters have none, which is the part that surprises people: a paragraph can open with a number, a quotation mark and a space and still resolve from a letter much further in.

Character classExamplesEffect on direction
Strong LTRLatin, Greek, Cyrillic, CJK lettersResolves the paragraph left-to-right
Strong RTLHebrew, Arabic, Syriac, Thaana lettersResolves the paragraph right-to-left
Weak0-9, Arabic-Indic digits, + - % $ €None — skipped, however many there are
NeutralSpace, . , ! ? ; : " ' ( ), emojiNone — skipped; takes the paragraph's direction once it is known
  • Digits never decide. 2026 was a good year resolves from w, and 2026 היה שנה טובה resolves from ה. Both are correct, and neither is affected by the year in front.
  • Nor does punctuation. An opening quotation mark, a bullet, or a bracket is neutral. The paragraph resolves from the first letter after it.
  • Emoji are neutral too. A line that is only emoji has nothing to resolve from at all — see below.

The gap

The paragraph with no letters in it

A paragraph made only of digits, punctuation or emoji has no strong character, so there is nothing for the first-strong rule to read. The empty paragraph you get from pressing Enter is the same case.

The specification has an answer for this and it is usually the wrong one for a document: dir="auto" falls back to the direction of the parent element. In a mixed document the parent is whatever the file was opened as, so an empty line in the middle of a Hebrew passage jumps to left-to-right, the caret lands on the wrong side, and the writer has to fight it back. Nothing is broken — the rule simply has no better information.

  • The fallback that behaves the way a writer expects is the direction of the paragraph above, not the direction of the file. A new line continues the passage it was created inside.
  • HTML cannot express that. dir="auto" is per-element and knows nothing about the element before it, so an editor that wants this behaviour has to compute direction itself.
  • At the very top of a document there is no paragraph above either. The only sensible fallback left is the direction of the interface language.

The marks

When a paragraph is not enough

Direction resolves per paragraph, but a paragraph can still contain a run of the other direction, and the neutral characters between the two runs have to attach to one of them. Almost always they attach correctly. When they don't, an invisible mark forces it.

Code pointNameWhat it is for
U+200ELeft-to-right mark LRMAn invisible strong LTR character. Pins neutrals beside it to left-to-right.
U+200FRight-to-left mark RLMThe mirror image. The usual fix for a full stop landing on the wrong side.
U+061CArabic letter mark ALMAs RLM, but of Arabic-letter type, so Arabic-Indic digits beside it behave.
U+2066U+2069Isolates LRI RLI FSI PDIWrap a run so it cannot affect the text around it. FSI resolves the run by first-strong — the right choice for text you did not write, such as a filename or a user's name.
  • Reach for an isolate before a mark when you are inserting text of unknown direction into a sentence. It is what the isolates were added for.
  • The older embedding controls U+202AU+202E still work and are best avoided: they have no scope, so a missing terminator corrupts the rest of the paragraph.
  • These characters are invisible and they are real. They survive copy and paste, count toward a length limit, and will not match a naive string comparison.

Reference

The right-to-left scripts

Right-to-left is not only Hebrew and Arabic. A first-strong implementation has to recognise all of these, or a document in one of them resolves the wrong way with no visible reason.

ScriptMain blockUsed for
HebrewU+0590–U+05FFHebrew, Yiddish, Ladino
ArabicU+0600–U+06FFArabic, Persian, Urdu, Pashto
SyriacU+0700–U+074FSyriac, Neo-Aramaic
ThaanaU+0780–U+07BFDhivehi (Maldives)
N'KoU+07C0–U+07FFManding languages of West Africa
SamaritanU+0800–U+083FSamaritan Hebrew and Aramaic
MandaicU+0840–U+085FMandaic
AdlamU+1E900–U+1E95FFulani

The editor this page came out of

PureOpen is a Markdown editor for Mac and iPhone that does all of the above without a setting. Every block resolves from its own first strong character, and a block with nothing to resolve from inherits the block above it rather than the file — the gap described further up. It is free, and the same rules apply to what it prints and exports to PDF.

PureOpen — Markdown editor with per-paragraph direction

Source, and when it was checked

  • The algorithm is Unicode Standard Annex #9, the Unicode Bidirectional Algorithm. The first-strong rule is clauses P2 and P3; the character classes are the Bidi_Class property in the Unicode Character Database.
  • dir="auto" is defined in the HTML Living Standard, which delegates to the same rule.
  • Script blocks checked against the Unicode Character Database on 31 August 2026.

Found something out of date or wrong? Tell us and it gets fixed — a reference nobody corrects stops being one.