Published on May 15, 2023

Implement RTL Support in Web Application

Melvin Liu

By Melvin Liu

Software Design | Engineering | Architecture

4 min read

share this post


Overview

Do you know that over 20 countries in the world read and write from right to left, such as Arabic, Hebrew, Persian, and Urdu? Without proper support, web applications designed for these languages can be confusing and difficult to read. That's why it's essential to consider Right-to-Left (RTL) support when building web applications.

I have the opportunity to work on a learning management system project abroad that needs to able their user to choose a variety of languages including several languages that are being read from right to left.

Thankfully, with the help of Tailwind CSS, implementing RTL support in your web applications is easier than you might think. Tailwind CSS provides pre-defined classes and features that make it easy to create responsive and customizable user interfaces that support RTL languages. we'll explore how to implement RTL support in web applications, particularly with Tailwind CSS and React/Nextjs.

RTL Example

What is TailwindCSS

Having been using this for years, using this for years, Tailwind CSS is a popular utility-first CSS framework that provides pre-defined classes for building responsive and customizable user interfaces. It supports RTL layouts out of the box, making it an ideal choice for building web applications with RTL languages.

Prerequisite

Enabling RTL support means that you need to implement multiple languages support first for your web applications. Basic knowledge of Internationalization(i18n) is required to implement RTL support.

Enabling RTL Support

So after you have created a multi-language website that can change the language of the content by switching the locale from the Navigation section, you need to do one more thing. Languages like Arabic needs RTL support. The content should be aligned from Right To Left.

So let us implement the RTL in our React-based app. HTML has built-in support for RTL. The below code will align the content from Right To Left.

<html dir="rtl" lang="ar">
</html>

Define Languages that require RTL

Create an array that consists of all languages that need right-to-left support

export const RTLLanguages = ['ur', 'ar', 'he']

ur stands for Urdu, ar stands for Arabic (standard), and he stands for Hebrew.

Dynamic HTML direction

Here is the implementation in _document.js that is a custom document in Next.js that can update <html> and <body> tags, implementation in other javascript based library/frameworks should be similar

import Document, {
    Html,
    Head,
    Main,
    NextScript,
    DocumentContext,
} from "next/document";
import React from "react";
import { RTLLanguages } from "constants/languages";

class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps, locale: ctx?.locale || "en" };
}

render() {
    return (
        <Html
            dir={RTLLanguages.includes(this.props.locale || "en") ? "rtl" : "ltr"}
            lang={this.props.locale}>
            <Head></Head>
            <body>
            <Main />
            <NextScript />
            </body>
        </Html>
    );
    }
}

This will enable the RTL feature in our Next.js app. But only after refreshing the page, we can see the difference. To overcome this issue, we can use the useEffect hook. The below code will inject the dir and lang attributes to the <html> tag if there is a change in browser locale.

//_app.ts
import "../styles/globals.css";
import React, { useEffect } from "react";
import { appWithTranslation } from "next-i18next";
import { useRouter } from "next/router";
import { QueryClient, QueryClientProvider } from "react-query";
import { GlobalStateProvider } from "context/GlobalStateProvider";
import { RTLLanguages } from "constants/languages";

function MyApp({ Component, pageProps }: any): React.ReactElement {
const { locale = "en" } = useRouter();
const queryClient = new QueryClient();

useEffect(() => {
    const dir = RTLLanguages.includes(locale) ? "rtl" : "ltr";
    document?.querySelector("html")?.setAttribute("dir", dir);
    document?.querySelector("html")?.setAttribute("lang", locale);
}, [locale]);

return (
    <QueryClientProvider client={queryClient}>
    <GlobalStateProvider>
        <Component {...pageProps} />
    </GlobalStateProvider>
    </QueryClientProvider>
);
}

Styling

You might notice, that right-to-left will change the direction of your web application, everything will be reversed or started from the right side of your screen. Several contents in your web application might look messy since you style the web app from the left side (let's say you define a margin-right, padding-right, etc, all of this style implementation won't look appropriate from the right side of your screen). In TailwindCSS this problem is already tackled by Tailwind Team. I personally use TailwindCSS v3.3.2 (by the time I write this blog, it is still part of the experimental feature) which already has built-in support for RTL languages. There is also a third-party plugin designed for Tailwind CSS v2 called tailwindcss-rtl, which is forward-compatible and stable.

For Tailwind v3 you can read https://tailwindcss.com/blog/tailwindcss-v3#rtl-and-ltr-modifiers, for v2 you can read tailwindcss-rtl

Best Practices

this article from material design blog is sufficient as a handbook for best practices implementation in bidirectionality in both web and mobile app. Go check them out!

You can find me on
Twitter: https://twitter.com/mlven23
GitHub: https://github.com/melvnl
LinkedIn: https://www.linkedin.com/in/melvin-liu/

Note: If you have any questions, you can leave a message below by Sign In with your GitHub account 😉