RTL Guidelines
==============

RTL languages such as Arabic, Hebrew, Persian and Urdu are read and
written from right-to-left, and the user interface for these languages
should be mirrored to ensure the content is easy to understand.

When a UI is changed from LTR to RTL (or vice-versa), it’s often called
mirroring. An RTL layout is the mirror image of an LTR layout, and it
affects layout, text, and graphics.

In RTL, anything that relates to time should be depicted as moving from
right to left. For example, forward points to the left, and backwards
points to the right.

Mirroring layout
~~~~~~~~~~~~~~~~

When a UI is mirrored, these changes occur:

-  Text fields icons are displayed on the opposite side of a field
-  Navigation buttons are displayed in reverse order
-  Icons that communicate direction, like arrows, are mirrored
-  Text is usually aligned to the right

In CSS, while it's possible to apply a rule for LTR and a separate one
specifically for RTL, it's usually better to use CSS `Logical Properties <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties>`_
which provide the ability to control layout through logical, rather than
physical mappings.

+---------------------------------------------------------+--------------------------------------------------+
| Do                                                      | Don't do                                         |
+---------------------------------------------------------+--------------------------------------------------+
| ``margin-inline-start: 5px``                            | ``margin-left: 5px``                             |
+---------------------------------------------------------+--------------------------------------------------+
| ``padding-inline-end: 5px``                             | ``padding-right: 5px``                           |
+---------------------------------------------------------+--------------------------------------------------+
| ``float: inline-start``                                 | ``float: left``                                  |
+---------------------------------------------------------+--------------------------------------------------+
| ``inset-inline-start: 5px``                             | ``left: 5px``                                    |
+---------------------------------------------------------+--------------------------------------------------+
| ``border-inline-end: 1px``                              | ``border-right: 1px``                            |
+---------------------------------------------------------+--------------------------------------------------+
| ``border-{start/end}-{start/end}-radius: 2px``          | ``border-{top/bottom}-{left/right}-radius: 2px`` |
+---------------------------------------------------------+--------------------------------------------------+
| ``padding: 1px 2px``                                    | ``padding: 1px 2px 1px 2px``                     |
+---------------------------------------------------------+--------------------------------------------------+
| ``margin-block: 1px 3px`` && ``margin-inline: 4px 2px`` | ``margin: 1px 2px 3px 4px``                      |
+---------------------------------------------------------+--------------------------------------------------+
| ``text-align: start`` or ``text-align: match-parent``   | ``text-align: left``                             |
| (depends on the context)                                |                                                  |
+---------------------------------------------------------+--------------------------------------------------+

When there is no special RTL-aware property available, or when
left/right properties must be used specifically for RTL, use the pseudo
``:-moz-locale-dir(rtl)`` (for XUL documents) or ``:dir(rtl)`` (for HTML
documents).

For example, this rule covers LTR to display searchicon.svg 7 pixels
from the left:

.. code:: css

   .search-box {
     background-image: url(chrome://path/to/searchicon.svg);
     background-position: 7px center;
   }

but an additional rule is necessary to cover RTL and place the search
icon on the right:

.. code:: css

   .search-box:dir(rtl) {
     background-position-x: right 7px;
   }

.. warning::

   It may be inappropriate to use logical properties when embedding LTR
   within RTL contexts. This is described further in the document.

Mirroring elements
~~~~~~~~~~~~~~~~~~

RTL content also affects the direction in which some icons and images
are displayed, particularly those depicting a sequence of events.

What to mirror
^^^^^^^^^^^^^^

-  Icons or animations that imply directionality or motion like
   back/forward buttons or progress bars
-  Icons that imply text direction, like
   `reader-mode.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/browser/themes/shared/icons/reader-mode.svg>`__
-  Icons that imply location of UI elements in the screen, like
   `sidebars-right.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/browser/themes/shared/icons/sidebars-right.svg>`__,
   `open-in-new.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/toolkit/themes/shared/icons/open-in-new.svg>`__,
   `default theme's preview.svg <https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/toolkit/mozapps/extensions/default-theme/preview.svg>`__
   or
   `pane-collapse.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/debugger/images/pane-collapse.svg>`__
-  Icons representing objects that are meant to be handheld should look
   like they're being right-handed, like the `magnifying glass
   icon <https://searchfox.org/mozilla-central/rev/e7c61f4a68b974d5fecd216dc7407b631a24eb8f/toolkit/themes/windows/global/icons/search-textbox.svg>`__
-  Twisties in their collapsed state. Note that if the context in which
   they appear is LTR (e.g. code in a devtools HTML view), they should
   not be mirrored, even if the user might be using an RTL locale.

What NOT to mirror
^^^^^^^^^^^^^^^^^^

-  Text/numbers
-  Icons containing text/numbers
-  Icons/animations that are direction neutral
-  Icons that wouldn't look differently if they'd be mirrored, like `X
   buttons <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/devtools/client/debugger/images/close.svg>`__
   or the `bookmark
   star <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/browser/themes/shared/icons/bookmark-hollow.svg>`__
   icon, or any other symmetric icon
-  Icons that should look the same as LTR, like icons related to code
   (which is always LTR) like
   `tool-webconsole.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/themes/images/tool-webconsole.svg>`__
-  Checkmark icons
-  Video/audio player controls
-  Product logos
-  Order of size dimensions (e.g., ``1920x1080`` should not become
   ``1080x1920``)
-  Order of size units (e.g., ``10 px`` should not become ``px 10``
   (unless the size unit is localizable))

How
^^^

The most common way to mirror images is by flipping the X axis:

.. code:: css

   transform: scaleX(-1);

Or, if you're already using ``transform`` with a different value on the same
element, you can also use `scale`:

.. code:: css

   scale: -1 1;

Note that mirroring images that way doesn't work when the image is a part of
an element with text using ``background-image``, because then the text would
be mirrored along with the image, and the image would be positioned incorrectly.
For such cases, try to use a different method for displaying the image,
like having it as an element all on its own.
If that's not possible, add a separate pre-mirrored image asset and specify
it in a separate ``:dir(rtl)`` rule:

.. code:: css

   .element-with-icon {
     background-image: url("path/to/image/image.svg");
   }

   .element-with-icon:dir(rtl) {
     background-image: url("path/to/image/image-rtl.svg");
   }

For animations like a progress bar, when using ``@keyframes`` to change
the ``transform: translateX()`` states, make sure to add a different
``@keyframes`` suited for RTL, and target that in a separate ``:dir()`` rule:

.. code:: css

   #progressbar {
     animation: progressbar-animation 1s linear infinite;
   }

   #progressbar:dir(rtl) {
     animation-name: progressbar-animation-rtl;
   }

   @keyframes progressbar-animation {
     0% {
       transform: translateX(-100px);
     }
     100% {
       transform: translateX(0);
     }
   }

   @keyframes progressbar-animation-rtl {
     0% {
       transform: translateX(100px);
     }
     100% {
       transform: translateX(0);
     }
   }

Likewise, if you're using ``transform-origin``, make sure to specify the
correct origin for RTL:

.. code:: css

   #progressbar {
     transform-origin: 0 0;
   }

   #progressbar:dir(rtl) {
     transform-origin: 100% 0;
   }

LTR text inside RTL contexts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default, in RTL locales, some symbols like ``/`` and ``.`` will be moved
around and won't be displayed in the order that they were typed in. This
may be problematic for URLs for instance, where you don't want dots to
change position.

Here's a non-exhaustive list of elements that should be displayed like
they would be in LTR locales:

-  Paths (e.g., C:\\Users\\username\\Desktop)
-  Full URLs
-  Code and code containers (like the DevTools' Inspector or the CSS
   rules panel)
-  about:config preference names and values
-  Telephone numbers
-  Usernames & passwords (most sites on the web expect LTR
   usernames/passwords, but there may be exceptions)
-  Other text fields where only LTR text is expected

To make sure these are displayed correctly, you can use one of the
following on the relevant element:

-  ``direction: ltr``
-  ``dir="ltr"`` in HTML

Since the direction of such elements is forced to LTR, the text will
also be aligned to the left, which is undesirable from an UI
perspective, given that is inconsistent with the rest of the RTL UI
which has text usually aligned to the right. You can fix this using
``text-align: match-parent``. In the following screenshot, both text
fields (username and password) and the URL have their direction set to
LTR (to display text correctly), but the text itself is aligned to the
right for consistency with the rest of the UI:

.. image:: about-logins-rtl.png
   :alt: about:logins textboxes in RTL layout

However, since the direction in LTR, this also means that the start/end
properties will correspond to left/right respectively, which is probably
not what you expect. This means you have to use extra rules instead of
using logical properties.

Here's a full code example:

.. code:: css

   .url {
     direction: ltr; /* Force text direction to be LTR */

     /* `start` (the default value) will correspond to `left`,
      * so we match the parent's direction in order to align the text to the right */
     text-align: match-parent;
   }

   /* :dir(ltr/rtl) isn't meaningful on .url, since it has direction: ltr, hence
    * why it is matched on .container. */
   .container:dir(ltr) .url {
     padding-left: 1em;
   }

   .container:dir(rtl) .url {
     padding-right: 1em;
   }

.. note::

   The LTR rule is separate from the global rule to avoid having the
   left padding apply on RTL without having to reset it in the RTL rule.

Auto-directionality
^^^^^^^^^^^^^^^^^^^

Sometimes, the text direction on an element should vary dynamically
depending on the situation. This can be the case for a search input for
instance, a user may input a query in an LTR language, but may also
input a query in a RTL language. In this case, the search input has to
dynamically pick the correct directionality based on the first word, in
order to display the query text correctly. The typical way to do this is
to use ``dir="auto"`` in HTML. It is essential that
``text-align: match-parent`` is set, to avoid having the text alignment
change based on the query, and logical properties also cannot be used on
the element itself given they can change meaning depending on the query.

Testing
~~~~~~~

To test for RTL layouts in Firefox, you can go to about:config and
set ``intl.l10n.pseudo`` to ``bidi``, or select the ``Enable "bidi" locale``
option in the 3-dots menu in the :doc:`Browser Toolbox </devtools-user/browser_toolbox/index>`.
The Firefox UI should immediately flip, but a restart may be required
to take effect in some Firefox features and interactions.

.. note::

   When testing with ``intl.l10n.pseudo`` set to ``bidi``, you may see some
   oddities regarding text ordering due to the nature of displaying LTR
   text in RTL layout.

   .. image:: about-protections-rtl.png
      :alt: about:protections in RTL layout- English vs. Hebrew

   This shouldn't be an issue when using an actual RTL build or language pack.

How to spot RTL-related issues
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-  Punctuation marks should appear on the left side of a
   word/sentence/paragraph on RTL, so if a *localizable* string appears
   in the UI with a dot, colon, ellipsis, question or exclamation mark
   on the right side of the text, this probably means that the text
   field is forced to be displayed as LTR.
-  If icons/images/checkmarks do not appear on the opposite side of
   text, when compared to LTR.
-  If buttons (like the close button, "OK" and "Cancel" etc.) do not
   appear on the opposite side of the UI and not in the opposite order,
   when compared to LTR.
-  If paddings/margins/borders are not the same from the opposite side,
   when compared to LTR.
-  Although Hebrew uses ``1 2 3``, all the other RTL locales we support
   should use ``١ ٢ ٣`` as digits. So if you see ``1 2 3`` on any such
   locale, that likely indicates a bug.
-  If navigating in the UI using the left/right arrow keys does not
   select the correct element (i.e., pressing Left selects an item on
   the right).
-  If navigating in the UI using the Tab key does not focus elements
   from right to left, in an RTL context.
-  If code is displayed as RTL (e.g., ``;padding: 20px`` - the semicolon
   should appear on the right side of the code). Code can still be
   aligned to the right if it appears in an RTL context.

See also
~~~~~~~~

-  `RTL Best
   Practices <https://docs.google.com/document/d/1Rc8rvwsLI06xArFQouTinSh3wNte9Sqn9KWi1r7xY4Y/edit#heading=h.pw54h41h12ct>`__
-  Building RTL-Aware Web Apps & Websites: `Part
   1 <https://hacks.mozilla.org/2015/09/building-rtl-aware-web-apps-and-websites-part-1/>`__,
   `Part
   2 <https://hacks.mozilla.org/2015/10/building-rtl-aware-web-apps-websites-part-2/>`__

Credits
~~~~~~~

Google's `Material Design guide for
RTL <https://material.io/design/usability/bidirectionality.html>`__
