Right to Left UI

In a right-to-left, top-to-bottom script (commonly shortened to right to left or abbreviated RTL), writing starts from the right of the page and continues to the left. This can be contrasted against left-to-right writing systems, where writing starts from the left of the page and continues to the right.

Arabic, Hebrew, Persian, and Urdu Sindhi are the most widespread RTL writing systems in modern times.

How RTL works in HTML

You can control the direction of text in the rendered HTML using the dir attribute. The default value is ltr

Looking at the English sentence, it will appear as if it's simply right aligned. But the directional flow of the content has actually changed. This becomes more evident with a table element.

Setting direction for an entire page

If you're building an entire page in an RTL language you'll most likely want to set the dir attribute only once, on a top level <div>.

In contrast, setting dir on the <body> or <html> element will change the position of the scrollbars in SOME browsers (IE, Opera), which may seem technically correct, but is actually not expected by most RTL reading users.

<body>
<div dir="rtl">My page goes in here!</div>
</body>

Dealing with unknown direction like user input

Sometimes you don't know beforehand what direction you want to render. HTML5 added an auto value to the dir attribute to help with that. The auto value tells the browser to look at the first strongly typed character in the element and work out from that what the base direction of the element should be. This is supported in most but not all browsers (yes, you correctly guessed which one).

Beware: Some input values, like an e-mail address will still be expected to be written left-to-right, even if the language spoken is right-to-left.

Dealing with numbers

Here's another edge case: Although Arabic text is written right-to-left, numbers are written the same way as in left-to-right languages. So the number 321 (three hundred and twenty one) is written ٣٢١ ("321", not "123").

Take care if you format numbers and insert spacing, like in a phone number. Illustrated below:

Notice how one of the phone numbers have been scrambled? A <span dir="ltr"> is used here to display the formatted number correctly.

How RTL works in CSS

Dealing with direction in HTML was fairly trivial. Now, how do we make sure our CSS layouts are bi-directional. Unfortunately, it gets a little trickier.

To illustrate, let's say I want to apply a margin after an element, like the following:

Ok, looks good. Now if we change the direction of the HTML element:

Oh dear! The margin is no longer "after" the element, but before. This is because values like left and right become ambiguous in a bi-directional context.

How to write CSS in a bi-directional world?

So how do we fix this? There are essentially two solutions to the problem:

  1. Replacing/overwriting everything that is "left" to be "right"
  2. Using CSS Logical Properties

Let's take a closer look:

1. Replacing left with right and vice versa

It may seem like a joke, but the easiest way to deal with this is simply by swapping all directional values with each other. Change margin-right to margin-left etc. Then using a CSS selector like div[dir=rtl] you can apply styles in the right context. This works, but does not scale very well.

Replacing all directional CSS properties manually will make you want to quit your job sooner than later. The good news is that some clever people have figured out that this process can be completely automated. There are a range of tools, including a PostCSS RTL Plugin, that will do this job for you. This will allow you to create one LTR and one RTL CSS file. This works surprisingly well.

2. Using CSS Logical Properties

In the past, CSS has tied itself to physical dimensions and directions, physically mapping the placement of elements to the left, right and top and bottom.

CSS Logical Properties, do not. You could theoretically replace all non-logical values with logical ones in your CSS, and it should then work in a bi-directional context without any further modification.

Instead of margin-right we'll use margin-inline-end to fix our previous example:

The main drawbacks (as of now) with CSS Logical Properties is lacking browser support, and that you would have to forbid any use of non-logical properties like left, or everything will start to break down quickly.

How RTL works in VCC UI

In VCC UI, we're using the PostCSS replacement strategy. It's all automated via a fela plugin, so you shouldn't have to think about it too much.

To render your page in RTL with VCC UI you have to do two things.

  1. Set dir=rtl to the top level surrounding HTML element
  2. Set the current locale on <ConfigProvider>, or an explicit direction on <ThemePicker>

Examples

<ConfigProvider config={{ locale: locale }}>
<div dir={locale.startsWith('ar') || locale.startsWith('he') ? 'rtl' : 'ltr'}>
<App />
</div>
</ConfigProvider>
<ThemePicker direction={isRtl ? 'rtl' : 'ltr'}>
<div dir={isRtl ? 'rtl' : 'ltr'}>
<App />
</div>
</ThemePicker>

Only want to render part of a page in RTL? No problem. You can use multiple theme providers, and even nest them.

Recommended Reading:

Want to dive deeper into RTL, here are some external articles that dive deeper into the subject:

2024 © Volvo Car Corporation