Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ragaeeb/dyelight/llms.txt

Use this file to discover all available pages before exploring further.

DyeLight provides full support for right-to-left (RTL) text rendering, making it suitable for Arabic, Hebrew, Persian, and other RTL languages.

Using the dir prop

Set the text direction using the dir prop:
import { DyeLight } from 'dyelight';

function RTLEditor() {
    const [text, setText] = useState('مرحبا بالعالم');

    return (
        <DyeLight
            value={text}
            onChange={setText}
            dir="rtl"  // Enable right-to-left rendering
            className="font-arabic text-lg"
        />
    );
}

Direction options

ValueDescription
"ltr"Left-to-right (default) - for English, Spanish, etc.
"rtl"Right-to-left - for Arabic, Hebrew, Persian, etc.

How RTL rendering works

When dir="rtl" is set, DyeLight automatically:
  1. Applies direction to both layers - The textarea and highlight overlay both receive dir="rtl"
  2. Adjusts scrollbar compensation - Scrollbars appear on the left side in RTL mode
  3. Preserves text flow - Unicode bidirectional algorithm is respected

Scrollbar positioning

The highlight synchronization system (in src/hooks/useHighlightSync.ts) automatically adjusts padding based on text direction:
const isRTL = computedStyle.direction === 'rtl';
if (scrollbarWidth > 0) {
    if (isRTL) {
        // Add padding to left side for RTL scrollbar
        const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;
        highlightLayer.style.paddingLeft = `${paddingLeft + scrollbarWidth}px`;
    } else {
        // Add padding to right side for LTR scrollbar
        const paddingRight = parseFloat(computedStyle.paddingRight) || 0;
        highlightLayer.style.paddingRight = `${paddingRight + scrollbarWidth}px`;
    }
}
This ensures the highlight overlay stays pixel-perfect aligned with the textarea text, even when scrollbars appear.
Scrollbar compensation happens automatically - you don’t need to handle it manually.

Bidirectional text handling

DyeLight preserves the browser’s native bidirectional text algorithm through careful CSS styling:

Line-level bidi inheritance

Each line wrapper inherits the bidirectional context:
const BIDI_LINE_STYLE: React.CSSProperties = {
    unicodeBidi: 'inherit',
};
This allows the line to respect the overall dir setting.

Span-level bidi normalization

Highlight spans use normal bidirectional behavior:
const BIDI_SPAN_STYLE: React.CSSProperties = {
    unicodeBidi: 'normal',
};
This ensures that highlighted portions don’t break the text flow.
These styles are automatically applied - you don’t need to configure them.

RTL examples

Arabic text with highlighting

import { useState } from 'react';
import { DyeLight, HighlightBuilder } from 'dyelight';

function ArabicEditor() {
    const [text, setText] = useState('مرحبا بالعالم\nهذا مثال للنص العربي');

    // Highlight the word "مرحبا" (Hello)
    const highlights = HighlightBuilder.words(
        text,
        ['مرحبا'],
        'bg-yellow-200'
    );

    return (
        <DyeLight
            value={text}
            onChange={setText}
            dir="rtl"
            highlights={highlights}
            className="font-arabic text-lg p-4"
            rows={6}
        />
    );
}

Hebrew text with pattern matching

import { useState } from 'react';
import { DyeLight, HighlightBuilder } from 'dyelight';

function HebrewEditor() {
    const [text, setText] = useState('שלום עולם\nזה דוגמה לטקסט עברי');

    // Highlight Hebrew words using regex
    const highlights = HighlightBuilder.pattern(
        text,
        /[\u0590-\u05FF]+/g,  // Hebrew Unicode range
        'text-blue-600 font-semibold'
    );

    return (
        <DyeLight
            value={text}
            onChange={setText}
            dir="rtl"
            highlights={highlights}
            className="font-hebrew p-4"
        />
    );
}

Mixed bidirectional text

DyeLight handles mixed LTR/RTL content correctly:
function MixedTextEditor() {
    const [text, setText] = useState(
        'English text مع نص عربي and back to English'
    );

    return (
        <DyeLight
            value={text}
            onChange={setText}
            dir="ltr"  // Primary direction
            className="p-4"
        />
    );
}
The browser’s Unicode bidirectional algorithm automatically handles embedded RTL/LTR segments within the text.

Styling RTL text

When styling RTL text, consider:

Font selection

Use appropriate fonts for your target language:
<DyeLight
    value={arabicText}
    onChange={setArabicText}
    dir="rtl"
    className="font-['Noto_Nastaliq_Urdu'] text-lg"
/>

Text alignment

Text automatically aligns to the right in RTL mode. You can override with CSS:
<DyeLight
    value={text}
    onChange={setText}
    dir="rtl"
    className="text-center"  // Center alignment
/>

Container styling

Apply RTL-aware spacing:
<DyeLight
    value={text}
    onChange={setText}
    dir="rtl"
    containerClassName="pr-4 pl-2"  // Right padding larger (start of text)
    className="p-4"
/>

Implementation details

The RTL implementation is in src/DyeLight.tsx:
export const getHighlightLayerStyle = (
    dir: React.CSSProperties['direction'],
    textareaHeight?: number,
): React.CSSProperties => ({
    ...DEFAULT_HIGHLIGHT_LAYER_STYLE,
    direction: dir,  // Apply direction to overlay
    height: textareaHeight ? `${textareaHeight}px` : undefined,
});
Both the textarea and overlay receive the same dir attribute:
<div dir={dir} ref={highlightLayerRef} style={highlightLayerStyle}>
    {highlightedContent}
</div>

<textarea
    dir={dir}
    // ... other props
/>
This ensures perfect synchronization between the two layers.

Browser support

RTL support works in all modern browsers:
  • Chrome 60+
  • Firefox 60+
  • Safari 12+
  • Edge 79+
Older browsers may have inconsistent bidirectional text rendering. Test thoroughly if you need to support legacy browsers.