A paragraph in Arabic or Hebrew runs from right to left. A paragraph in English runs from left to right. Many documents contain both, sometimes in the same sentence: an English product name inside an Arabic sentence, or a phone number that has to stay in its original order. Most of the time the browser handles this correctly without help. The failures come when the editor adds structure: a list that indents on the wrong side, a heading aligned to the left in a right-to-left document, or a stray invisible character that moves punctuation to the wrong end of a line.
Let each block pick its direction
The base direction belongs to each block, not to the whole editor. A paragraph that begins with an Arabic word should be right-to-left, and the next paragraph that begins with English should not inherit that. The dir="auto" attribute does this: the browser looks at the first strong character in the block and chooses the direction from it. The CSS equivalent is unicode-bidi: plaintext:
.rte-content p,
.rte-content li,
.rte-content h1,
.rte-content h2,
.rte-content h3,
.rte-content blockquote {
unicode-bidi: plaintext; /* each block takes the direction of its first strong character */
text-align: start; /* "start" follows the block's direction, so no left/right hard-coding */
}With text-align: start, an Arabic paragraph aligns to the right and an English one to the left, without a single rule that names a side.
Use logical properties for indentation
Lists, quotes and code blocks are indented with padding and margins. If those are written as left and right, they stay on the left in a right-to-left paragraph, and the bullet points end up on the wrong side of the text. Logical properties name the side by reading order instead:
/* Instead of padding-left, margin-left, border-left: */
.rte-content ul,
.rte-content ol,
.rte-content blockquote {
padding-inline-start: 1.5rem; /* left in English, right in Arabic */
margin-inline: 0;
}
.rte-content blockquote {
border-inline-start: 3px solid #cbd5e1;
}The same applies to floats, positioned elements and icons that point a direction. Anything that says “before the text” should use the start and end terms, not left and right.
Do not store invisible direction marks
When a punctuation mark lands on the wrong side of an English name in an Arabic sentence, the quick fix is to insert a directional mark: U+200E (left-to-right mark) or U+200F (right-to-left mark). It works on screen and is a trap in storage. The mark is invisible, but it travels with the text. It appears in copy and paste, it breaks exact-match search, it changes character counts, and it stays in the document long after the bug is forgotten.
Use markup instead. Wrap the English run in a bdi element, which isolates its direction from the surrounding text, or give it an explicit dir:
<p dir="rtl">
الاسم التجاري هو <bdi>RichTextEditor</bdi> وهو مكتوب بالإنجليزية.
</p>The bdi element is the right tool when the direction of the inner text is unknown or different from the outer one, such as a user name or a product name. It is harmless to store, and a search for the English name still matches.
Keep dir, and allow only safe values
A sanitiser that strips unknown attributes will remove dir unless it is allowed on purpose. Keep it, and check the value, because it is copied straight into the stored HTML:
const ALLOWED_DIR = new Set(["ltr", "rtl", "auto"]);
function cleanDir(value: string | null): string | null {
const normal = value?.trim().toLowerCase() ?? "";
return ALLOWED_DIR.has(normal) ? normal : null;
}Apply it to the elements that carry direction in your editor, such as paragraphs, list items, headings and table cells. A paste from another document can bring dir values from that document, and the filter should decide which of them survive.
Test with real mixed content
Right-to-left bugs rarely appear with a single Arabic sentence. Build a short fixture of mixed cases and check each one in the editor and in the saved output:
- An Arabic paragraph that ends with an English product name and a full stop.
- An English paragraph that starts with a Hebrew word.
- A numbered list in each direction, with the numbers on the correct side.
- A phone number and a date inside an Arabic sentence, checking that digits keep their order.
- Pressing the arrow keys across a boundary between the two directions, which moves the caret in visual order.
- Copying a mixed paragraph and pasting it into a plain text field.
Keyboard direction switching is also part of the experience. Users on Windows and macOS switch input direction with different keys, and the editor should not block those keys. Check it on each platform rather than assuming the browser takes care of it.
RichTextEditor is a perpetual-licence JavaScript editor — one purchase, self-hosted, no metered editor loads. Download the evaluation or see how it compares.