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-leftbecomesmargin-inline-startmargin-rightbecomesmargin-inline-endpadding-leftbecomespadding-inline-startpadding-rightbecomespadding-inline-endleft(in positioning) becomesinset-inline-startright(in positioning) becomesinset-inline-endtext-align: leftbecomestext-align: starttext-align: rightbecomestext-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.