Supporting right-to-left (RTL) layouts

Adapting your layout for languages like Arabic and Hebrew

Problem

An application's layout is built with CSS properties like margin-left and padding-right, which assume a left-to-right (LTR) text direction. When the application is translated into an RTL language like Arabic or Hebrew, the entire layout appears backward, with content misaligned and unreadable.

Solution

Switch from directional CSS properties (left/right) to their modern, direction-agnostic logical equivalents (start/end). Set the dir attribute on the <html> element based on the current language, and the browser will automatically flip the layout correctly.

Steps

1. Define which languages are RTL

First, you need a way to know which of your supported languages are RTL.

Create a new file app/i18n-config.ts (or update your existing one) to store this information.

// i18n-config.ts

export const locales = ['en', 'es', 'ar', 'he']; // ar=Arabic, he=Hebrew
export const defaultLocale = 'en';
export const localeCookieName = 'NEXT_LOCALE';

export const rtlLocales = ['ar', 'he'];

2. Set the dir attribute in the root layout

Modify your app/[lang]/layout.tsx to conditionally add the dir (direction) attribute to the <html> tag.

// app/[lang]/layout.tsx
import { rtlLocales } from '@/i18n-config';

export async function generateStaticParams() {
  return [{ lang: 'en' }, { lang: 'es' }, { lang: 'ar' }, { lang: 'he' }];
}

export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { lang: string };
}) {
  // Determine if the current language is RTL
  const isRtl = rtlLocales.includes(params.lang);

  return (
    <html lang={params.lang} dir={isRtl ? 'rtl' : 'ltr'}>
      <body>
        {/* ...your providers and content... */}
        {children}
      </body>
    </html>
  );
}

By adding dir="rtl" to the <html> tag, you are telling the browser that the entire document flow should be from right to left for this page.

3. Update CSS to use logical properties

Go through your global CSS and component styles. Replace all directional properties with their logical equivalents.

  • margin-left becomes margin-inline-start
  • margin-right becomes margin-inline-end
  • padding-left becomes padding-inline-start
  • padding-right becomes padding-inline-end
  • left (in positioning) becomes inset-inline-start
  • right (in positioning) becomes inset-inline-end
  • text-align: left becomes text-align: start
  • text-align: right becomes text-align: end

Example:

Before (Directional):

.card {
  padding-left: 16px;
  border-left: 4px solid blue;
}
.title {
  text-align: left;
}

After (Logical):

.card {
  padding-inline-start: 16px;
  border-inline-start: 4px solid blue;
}
.title {
  text-align: start;
}

When a user visits /en (dir="ltr"), padding-inline-start is applied to the left. When a user visits /ar (dir="rtl"), the browser automatically applies padding-inline-start to the right, flipping your component layout correctly.