Skip to content

RTL

AWC UI components use CSS logical properties throughout, providing automatic right-to-left (RTL) layout support for Arabic, Hebrew, Persian, Urdu, and other RTL languages.

Set the dir="rtl" attribute on the <html> element or any ancestor:

<!-- Global RTL -->
<html dir="rtl" lang="ar">
<body>
<md-button variant="filled" icon="add">إضافة عنصر</md-button>
</body>
</html>
<!-- Scoped RTL section -->
<div dir="rtl">
<md-text-field variant="outlined" label="الاسم"></md-text-field>
<md-button variant="filled">إرسال</md-button>
</div>

All components use CSS logical properties instead of physical direction properties:

Physical (never used)Logical (always used)
margin-leftmargin-inline-start
margin-rightmargin-inline-end
padding-leftpadding-inline-start
padding-rightpadding-inline-end
leftinset-inline-start
rightinset-inline-end
border-leftborder-inline-start
border-rightborder-inline-end
text-align: lefttext-align: start
text-align: righttext-align: end
widthinline-size
heightblock-size

Directional icons (arrows, chevrons, navigation) automatically mirror in RTL:

:host-context([dir="rtl"]) .md-button__directional-icon,
:host([dir="rtl"]) .md-button__directional-icon {
transform: scaleX(-1);
}

Icons that are symmetric (checkmarks, plus signs, stars) do not mirror.

Layout mirrors automatically. Two things still need you:

An arrow or chevron is a glyph, not a box — CSS cannot know it points somewhere. Components that render directional icons expose mirror-icon:

<div dir="rtl">
<!-- flipped: the arrow follows the reading direction -->
<md-button trailing-icon="arrow_forward" mirror-icon>التالي</md-button>
<!-- NOT flipped: these glyphs mean the same in both directions -->
<md-button icon="add">إضافة</md-button>
<md-icon-button icon="search" aria-label="بحث"></md-icon-button>
</div>
Mirror theseNever mirror these
arrow_back arrow_forward chevron_left chevron_rightadd close search delete
send reply undo redofavorite star home settings
first_page last_page trending_flatClock faces, media play/pause

Where you supply the glyph name, you own the swap. The clearest case is md-transfer-list, whose mover buttons take explicit icons:

<md-transfer-list
move-right-icon="chevron_left"
move-left-icon="chevron_right"
move-all-right-icon="keyboard_double_arrow_left"
move-all-left-icon="keyboard_double_arrow_right"
></md-transfer-list>

The same applies to a directional trailing-icon on md-list-item, a custom back glyph slotted into md-side-sheet, or a chevron separator in md-breadcrumbs.

Every component includes RTL tests:

it('renders correctly in RTL context', async () => {
const page = await newSpecPage({
components: [MdButton],
html: `<div dir="rtl"><md-button icon="arrow_forward">التالي</md-button></div>`,
});
expect(page.root).toBeTruthy();
});
function RTLApp() {
return (
<div dir="rtl">
<MdButton variant="filled" icon="add">
إضافة عنصر
</MdButton>
</div>
);
}
<template>
<div dir="rtl">
<md-button variant="filled" icon="add">
إضافة عنصر
</md-button>
</div>
</template>
function setDirection(dir) {
document.documentElement.setAttribute('dir', dir);
}
// Auto-detect from language
const rtlLanguages = ['ar', 'he', 'fa', 'ur'];
const userLang = navigator.language.split('-')[0];
if (rtlLanguages.includes(userLang)) {
setDirection('rtl');
}

When overriding component styles, always use logical properties:

/* Correct — works in both LTR and RTL */
md-card {
padding-inline: 24px;
margin-inline-start: 16px;
border-inline-end: 1px solid var(--md-sys-color-outline);
}
/* Incorrect — breaks in RTL */
md-card {
padding-left: 24px;
padding-right: 24px;
margin-left: 16px;
border-right: 1px solid var(--md-sys-color-outline);
}