You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add bidirectional text (RTL) documentation page
Cover w:bidi paragraph layout, w:rtl run direction, logical
alignment (start/end), indentation flipping, tab stop measurement
from the leading edge, and mixed bidi documents. Includes live
preview examples and implementation notes from building RTL
support in SuperDoc.
Copy file name to clipboardExpand all lines: apps/web/src/data/docs.ts
+242Lines changed: 242 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -452,6 +452,248 @@ Each border element has:
452
452
],
453
453
},
454
454
455
+
"bidirectional-text": {
456
+
title: "Bidirectional Text (RTL)",
457
+
description:
458
+
"Right-to-left paragraph layout, run-level text direction, and how bidi interacts with alignment, indentation, and tab stops.",
459
+
badge: "w:bidi",
460
+
content: [
461
+
{
462
+
type: "paragraph",
463
+
text: "Bidirectional (bidi) support in OOXML handles right-to-left scripts like Arabic and Hebrew. It operates at two levels: `w:bidi` sets the paragraph's base direction, and `w:rtl` controls individual run reading order. Getting these right is the difference between text that renders correctly and text that's backwards.",
464
+
},
465
+
{type: "heading",level: 2,text: "Structure"},
466
+
{
467
+
type: "code",
468
+
code: `w:pPr (paragraph properties)
469
+
├── w:bidi Paragraph base direction (RTL layout)
470
+
├── w:jc Alignment — start/end are logical, flip with bidi
471
+
├── w:ind Indentation — start/end flip with bidi
472
+
└── w:tabs
473
+
└── w:tab Tab stops — measured from leading edge (right for RTL)
474
+
475
+
w:rPr (run properties)
476
+
├── w:rtl Run reading order (right-to-left)
477
+
├── w:cs Treat run as complex script
478
+
├── w:rFonts @w:cs — complex script font
479
+
└── w:lang @w:bidi — bidi language (ar-SA, he-IL, etc.)`,
480
+
},
481
+
{type: "heading",level: 2,text: "Paragraph Direction — w:bidi"},
482
+
{
483
+
type: "paragraph",
484
+
text: "The `w:bidi` element on `w:pPr` sets the paragraph's base direction to right-to-left. This flips four things: indentation (start/end swap sides), alignment (start/end resolve to opposite edges), tab stop measurement (from right edge instead of left), and text flow direction. It does NOT reorder characters within runs — that's `w:rtl`'s job.",
485
+
},
486
+
{
487
+
type: "preview",
488
+
title: "RTL paragraph with Arabic text",
489
+
xml: `<w:p>
490
+
<w:pPr>
491
+
<w:bidi/>
492
+
</w:pPr>
493
+
<w:r>
494
+
<w:rPr><w:rtl/></w:rPr>
495
+
<w:t>مرحبا بالعالم</w:t>
496
+
</w:r>
497
+
<w:r>
498
+
<w:t xml:space="preserve"> - Hello World</w:t>
499
+
</w:r>
500
+
</w:p>`,
501
+
},
502
+
{type: "heading",level: 2,text: "Alignment with Bidi"},
503
+
{
504
+
type: "paragraph",
505
+
text: 'The `w:jc` element uses logical values `start` and `end` that flip based on paragraph direction. `start` means the leading edge: left for LTR, right for RTL. `end` means the trailing edge. The values `left`, `right`, and `center` are always physical and don\'t flip. Arabic justify variants (`lowKashida`, `mediumKashida`, `highKashida`) extend joiners between characters instead of adding word spacing.',
506
+
},
507
+
{
508
+
type: "preview",
509
+
title: "RTL paragraph with center alignment",
510
+
xml: `<w:p>
511
+
<w:pPr>
512
+
<w:bidi/>
513
+
<w:jc w:val="center"/>
514
+
</w:pPr>
515
+
<w:r>
516
+
<w:rPr><w:rtl/></w:rPr>
517
+
<w:t>نص عربي في الوسط</w:t>
518
+
</w:r>
519
+
</w:p>`,
520
+
},
521
+
{
522
+
type: "preview",
523
+
title: "RTL paragraph — start alignment resolves to right",
524
+
xml: `<w:p>
525
+
<w:pPr>
526
+
<w:bidi/>
527
+
<w:jc w:val="start"/>
528
+
</w:pPr>
529
+
<w:r>
530
+
<w:rPr><w:rtl/></w:rPr>
531
+
<w:t>محاذاة البداية — تعني اليمين في الفقرات العربية</w:t>
["`distribute`","Justify (char + word spacing)","Justify (char + word spacing)"],
549
+
],
550
+
},
551
+
{type: "heading",level: 2,text: "Indentation with Bidi"},
552
+
{
553
+
type: "paragraph",
554
+
text: "The `w:ind` element uses `start`/`end` attributes that are logical — they refer to the leading and trailing edges of the paragraph. For an RTL paragraph, `start` is the right margin and `end` is the left margin. The `firstLine` and `hanging` attributes also apply relative to the start edge.",
555
+
},
556
+
{
557
+
type: "preview",
558
+
title: "RTL paragraph with start indent (appears on right side)",
559
+
xml: `<w:p>
560
+
<w:pPr>
561
+
<w:bidi/>
562
+
<w:ind w:start="720"/>
563
+
</w:pPr>
564
+
<w:r>
565
+
<w:rPr><w:rtl/></w:rPr>
566
+
<w:t>فقرة مع مسافة بادئة من اليمين</w:t>
567
+
</w:r>
568
+
</w:p>`,
569
+
},
570
+
{type: "heading",level: 2,text: "Tab Stops with Bidi"},
571
+
{
572
+
type: "paragraph",
573
+
text: "Tab stop positions in RTL paragraphs are measured from the right edge of the text area, not the left. The `w:tab` alignment values `start` and `end` also flip. A `start`-aligned tab in an RTL paragraph aligns text to the right of the tab position.",
574
+
},
575
+
{
576
+
type: "preview",
577
+
title: "RTL paragraph with dot leader tab stop",
578
+
xml: `<w:p>
579
+
<w:pPr>
580
+
<w:bidi/>
581
+
<w:tabs>
582
+
<w:tab w:val="left" w:pos="8640" w:leader="dot"/>
583
+
</w:tabs>
584
+
</w:pPr>
585
+
<w:r>
586
+
<w:rPr><w:rtl/></w:rPr>
587
+
<w:t>عنوان الفصل</w:t>
588
+
</w:r>
589
+
<w:r><w:tab/></w:r>
590
+
<w:r>
591
+
<w:rPr><w:rtl/></w:rPr>
592
+
<w:t>٤٢</w:t>
593
+
</w:r>
594
+
</w:p>`,
595
+
},
596
+
{type: "heading",level: 2,text: "Run-Level Direction — w:rtl"},
597
+
{
598
+
type: "paragraph",
599
+
text: "The `w:rtl` element on `w:rPr` sets the reading order of a single run to right-to-left. This is separate from `w:bidi` — you can have an LTR paragraph with RTL runs (inline Arabic in English text) or an RTL paragraph with LTR runs (English words in Arabic text). The spec warns: don't use `w:rtl` on strong LTR characters — behavior is undefined.",
600
+
},
601
+
{
602
+
type: "preview",
603
+
title: "LTR paragraph with inline Arabic run",
604
+
xml: `<w:p>
605
+
<w:r>
606
+
<w:t xml:space="preserve">English text then </w:t>
607
+
</w:r>
608
+
<w:r>
609
+
<w:rPr><w:rtl/></w:rPr>
610
+
<w:t>نص عربي</w:t>
611
+
</w:r>
612
+
<w:r>
613
+
<w:t xml:space="preserve"> then English again</w:t>
614
+
</w:r>
615
+
</w:p>`,
616
+
},
617
+
{type: "heading",level: 2,text: "Mixed Document — RTL and LTR Paragraphs"},
618
+
{
619
+
type: "preview",
620
+
title: "Document with alternating paragraph directions",
text: "`w:bidi` flips paragraph layout (indentation, alignment, tabs, text direction). `w:rtl` on `w:rPr` controls run reading order. You need both — without `w:rtl` on the runs, text lands in the right position but characters read backwards.",
647
+
},
648
+
{
649
+
type: "note",
650
+
noteType: "critical",
651
+
title: "Tab positions are from the right edge in RTL",
652
+
text: "Tab `pos` is measured from the leading edge (§17.3.1.37). For RTL, that's the right margin. If your layout engine always measures from the left, every RTL tab stop lands on the wrong side.",
653
+
},
654
+
{
655
+
type: "note",
656
+
noteType: "warning",
657
+
title: "start/end are logical, left/right are physical",
658
+
text: "`jc=\"start\"` flips with direction; `jc=\"left\"` does not. Don't resolve `start` → `left` during import — you'll lose the logical intent. Same applies to `w:ind start`/`end` attributes.",
659
+
app: "Word",
660
+
},
661
+
{
662
+
type: "note",
663
+
noteType: "info",
664
+
title: "Section bidi is separate from paragraph bidi",
665
+
text: "`w:sectPr > w:bidi` controls page chrome (page numbers, column order). It doesn't affect text. You need paragraph-level `w:bidi` for text layout.",
666
+
},
667
+
{type: "heading",level: 2,text: "Schema"},
668
+
{
669
+
type: "table",
670
+
headers: ["Element","Parent","Description"],
671
+
rows: [
672
+
["`w:bidi`","`w:pPr`","Paragraph base direction — sets RTL layout for indentation, alignment, tabs"],
673
+
["`w:rtl`","`w:rPr`","Run reading order — right-to-left character ordering"],
674
+
["`w:cs`","`w:rPr`","Complex script flag — forces complex script font/size"],
675
+
["`w:bidi`","`w:sectPr`","Section layout direction — page-level RTL (separate from paragraph bidi)"],
0 commit comments