<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammad Sadegh Majidi Kadkani</title>
    <description>The latest articles on DEV Community by Mohammad Sadegh Majidi Kadkani (@cmatrix1).</description>
    <link>https://dev.to/cmatrix1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3209438%2Fc18973dd-ebc4-4f88-b8da-c958ac0e70aa.jpeg</url>
      <title>DEV Community: Mohammad Sadegh Majidi Kadkani</title>
      <link>https://dev.to/cmatrix1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cmatrix1"/>
    <language>en</language>
    <item>
      <title>Building RTL (Persian/Arabic) Websites with Bootstrap 5: A Practical Guide</title>
      <dc:creator>Mohammad Sadegh Majidi Kadkani</dc:creator>
      <pubDate>Mon, 26 Oct 2026 12:07:12 +0000</pubDate>
      <link>https://dev.to/cmatrix1/building-rtl-persianarabic-websites-with-bootstrap-5-a-practical-guide-1bn2</link>
      <guid>https://dev.to/cmatrix1/building-rtl-persianarabic-websites-with-bootstrap-5-a-practical-guide-1bn2</guid>
      <description>&lt;p&gt;Getting a Persian or Arabic site to look right takes more than &lt;code&gt;text-align: right&lt;/code&gt;. Direction affects layout, spacing, icons, numbers, form fields and even your carousel arrows. Below is the checklist I use for every right-to-left (RTL) project with Bootstrap 5, plus a free starter template you can clone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; set &lt;code&gt;dir="rtl"&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;, load &lt;code&gt;bootstrap.rtl.min.css&lt;/code&gt;, use logical properties in your own CSS, flip only the icons that show direction, and test with real Persian/Arabic text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Start at the root: &lt;code&gt;lang&lt;/code&gt; and &lt;code&gt;dir&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"fa"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"rtl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dir="rtl"&lt;/code&gt; changes how the browser lays out the page: inline flow, table column order, scrollbar side in some browsers, and the default alignment of text. &lt;code&gt;lang&lt;/code&gt; matters too. It drives hyphenation, font selection, and screen reader pronunciation. Use &lt;code&gt;fa&lt;/code&gt; for Persian and &lt;code&gt;ar&lt;/code&gt; for Arabic.&lt;/p&gt;

&lt;p&gt;Don't set direction with CSS (&lt;code&gt;direction: rtl&lt;/code&gt; on &lt;code&gt;body&lt;/code&gt;). The HTML attribute is semantic, it's inherited by form controls, and the &lt;code&gt;:dir()&lt;/code&gt; selector and Bootstrap both rely on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use Bootstrap's official RTL build
&lt;/h2&gt;

&lt;p&gt;Since v5, Bootstrap ships a full RTL stylesheet generated with RTLCSS. Swap one file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
  &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.rtl.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you get for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ms-*&lt;/code&gt; / &lt;code&gt;me-*&lt;/code&gt; and &lt;code&gt;ps-*&lt;/code&gt; / &lt;code&gt;pe-*&lt;/code&gt; mean &lt;em&gt;start&lt;/em&gt; and &lt;em&gt;end&lt;/em&gt;, so in RTL &lt;code&gt;ms-3&lt;/code&gt; puts the margin on the &lt;strong&gt;right&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text-start&lt;/code&gt; aligns right, &lt;code&gt;float-end&lt;/code&gt; floats left, and so on.&lt;/li&gt;
&lt;li&gt;Navbar, dropdowns, input groups, breadcrumbs, pagination and modals are all mirrored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common trap: an icon placed before its label needs space at its &lt;em&gt;end&lt;/em&gt;, so it gets &lt;code&gt;me-2&lt;/code&gt; in both LTR and RTL. If you "fix" it to &lt;code&gt;ms-2&lt;/code&gt; because you think in left/right, the icon ends up stuck to the text. Think "start = where reading begins".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Sass?&lt;/strong&gt; Compile your own build and run it through &lt;a href="https://rtlcss.com/" rel="noopener noreferrer"&gt;RTLCSS&lt;/a&gt;. You can keep one source and produce &lt;code&gt;style.css&lt;/code&gt; and &lt;code&gt;style.rtl.css&lt;/code&gt;. Bootstrap uses the &lt;code&gt;/* rtl:ignore */&lt;/code&gt; and &lt;code&gt;/* rtl:raw: */&lt;/code&gt; directives for exceptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Write your own CSS with logical properties
&lt;/h2&gt;

&lt;p&gt;Your custom CSS isn't flipped automatically when you just use the CDN file. Logical properties remove the need for a second stylesheet:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Physical (avoid)&lt;/th&gt;
&lt;th&gt;Logical (use)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-left&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;margin-inline-start&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding-right&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;padding-inline-end&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;left: 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inset-inline-start: 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-left&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;border-inline-start&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-align: left&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text-align: start&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-top-left-radius&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;border-start-start-radius&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.sidebar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;inset-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* right in RTL, left in LTR */&lt;/span&gt;
  &lt;span class="py"&gt;border-inline-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--bs-border-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser support is universal in evergreen browsers. Transforms are the exception: &lt;code&gt;translateX(-100%)&lt;/code&gt; doesn't flip, so off-canvas animations need a direction-aware rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.sidebar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"ltr"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.sidebar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Fonts: pick one designed for Persian/Arabic
&lt;/h2&gt;

&lt;p&gt;System fallbacks for Persian vary a lot by OS and often look cramped. &lt;a href="https://github.com/rastikerdar/vazirmatn" rel="noopener noreferrer"&gt;Vazirmatn&lt;/a&gt; is a free (OFL) variable font with Persian and Arabic glyphs and good Latin support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
  &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--bs-body-font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vazirmatn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system-ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increase line-height.&lt;/strong&gt; Arabic-script letters have tall ascenders and dots below the baseline, so 1.5 often feels tight. 1.8–2 reads better for body text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't use &lt;code&gt;letter-spacing&lt;/code&gt;&lt;/strong&gt; on Persian/Arabic text. The script is cursive, and spacing breaks the joins between letters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Icons: flip only what shows direction
&lt;/h2&gt;

&lt;p&gt;Not every icon should be mirrored. A rule of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flip:&lt;/strong&gt; arrows, chevrons, "back/next", reply, send, undo/redo, list-with-bullets, progress indicators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't flip:&lt;/strong&gt; search, check marks, clocks (clocks run clockwise everywhere), media play buttons (debatable, but most RTL apps keep ▶), logos, and anything that shows a real-world object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Bootstrap Icons, just choose the opposite glyph in RTL (&lt;code&gt;bi-chevron-left&lt;/code&gt; for "next"), or add a utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"rtl"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.flip-rtl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bootstrap's carousel controls and breadcrumb separators are already handled by the RTL build.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Numbers, forms and mixed content
&lt;/h2&gt;

&lt;p&gt;This is where most RTL bugs live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Digits.&lt;/strong&gt; Persian users expect Persian digits (۰۱۲۳…) in content. Convert at render time, not in your data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toFa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;۰۱۲۳۴۵۶۷۸۹&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.fa-num&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toFa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For prices, &lt;code&gt;Intl.NumberFormat('fa-IR').format(1250000)&lt;/code&gt; gives &lt;code&gt;۱٬۲۵۰٬۰۰۰&lt;/code&gt; with the correct separator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inputs.&lt;/strong&gt; Fields like email, URL, phone, card numbers and codes should stay LTR even on an RTL page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control text-start"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"numeric"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the server, normalize what users type. Persian keyboards produce &lt;code&gt;۱۲۳&lt;/code&gt;, Arabic keyboards produce &lt;code&gt;١٢٣&lt;/code&gt;, so convert both to ASCII before validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixed direction text.&lt;/strong&gt; A phrase like "Bootstrap 5 RTL" inside a Persian sentence is usually fine. User-generated strings, usernames and anything ending in punctuation can jump around, though. Wrap them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;bdi&amp;gt;&lt;/span&gt;{{ username }}&lt;span class="nt"&gt;&amp;lt;/bdi&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ user_comment }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dir="auto"&lt;/code&gt; on text inputs and textareas also helps when users type in either language.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Tables, charts and third-party widgets
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tables mirror automatically with &lt;code&gt;dir&lt;/code&gt;, so the first column ends up on the right. Keep numeric columns right-aligned anyway (&lt;code&gt;text-end&lt;/code&gt; = left in RTL; pick deliberately).&lt;/li&gt;
&lt;li&gt;Charting libraries often need an explicit RTL option, such as reversed axes or a &lt;code&gt;rtl: true&lt;/code&gt; legend. CSS-only bar charts built with flexbox mirror for free.&lt;/li&gt;
&lt;li&gt;Date pickers: Persian sites usually need the Jalali (Solar Hijri) calendar. &lt;code&gt;Intl.DateTimeFormat('fa-IR')&lt;/code&gt; formats dates in that calendar out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Testing checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use real text&lt;/strong&gt;, not lorem ipsum. Persian words differ in length and shape, and layout bugs only show with real copy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toggle direction live&lt;/strong&gt; in DevTools (&lt;code&gt;document.documentElement.dir = 'ltr'&lt;/code&gt;). If anything that shouldn't move breaks, you have a physical property somewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search your CSS&lt;/strong&gt; for &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;margin-left&lt;/code&gt;, &lt;code&gt;padding-right&lt;/code&gt; and &lt;code&gt;translateX&lt;/code&gt;. Each one is a candidate bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check mobile off-canvas menus.&lt;/strong&gt; They are the most common RTL animation bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test form validation&lt;/strong&gt; with Persian digits and copy-pasted text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen reader pass.&lt;/strong&gt; With the correct &lt;code&gt;lang&lt;/code&gt;, VoiceOver and NVDA switch voices.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A free starter to skip the setup
&lt;/h2&gt;

&lt;p&gt;I put all of the above into a small MIT-licensed template: a landing page (hero, features, pricing, FAQ) and a dashboard (off-canvas sidebar, stat cards, CSS bar chart, table). It uses Bootstrap 5 RTL, Vazirmatn and a Persian-digit helper, with no jQuery and no build step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/Cmatrix1/rtl-html-starter" rel="noopener noreferrer"&gt;https://github.com/Cmatrix1/rtl-html-starter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://cmatrix1.github.io/rtl-html-starter/" rel="noopener noreferrer"&gt;https://cmatrix1.github.io/rtl-html-starter/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clone it, change &lt;code&gt;--brand&lt;/code&gt; in &lt;code&gt;style.css&lt;/code&gt;, and start writing content. If you need complete production templates (shop, admin panel, corporate), we also maintain a collection of &lt;a href="https://rtlhtml.ir/" rel="noopener noreferrer"&gt;Persian RTL HTML templates at RTLHTML&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Got an RTL bug that isn't covered here? Drop it in the comments and I'll add it to the checklist.&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>webdev</category>
      <category>bootstrap</category>
    </item>
  </channel>
</rss>
