RTL support in Flutter
By Charlin Joe · 8 December 2025
RTL (right-to-left) layout support is required for Arabic, Hebrew, Persian, and Urdu. Flutter has solid RTL support built in, but you need to set it up correctly and test it.
Enabling RTL support
MaterialApp(
// List supported locales
supportedLocales: const [
Locale('en'),
Locale('ar'), // Arabic
Locale('he'), // Hebrew
],
// Delegate that provides RTL directionality
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
AppLocalizations.delegate, // Your generated strings
],
// Optionally force RTL for testing
// builder: (context, child) => Directionality(textDirection: TextDirection.rtl, child: child!),
)
dependencies:
flutter_localizations:
sdk: flutter
intl: ^0.19.0
How Flutter handles RTL automatically
When TextDirection.rtl is active:
Rowchildren reverse orderPadding(left: 16)becomes right paddingAlignment.centerLeftbecomes center-rightIcons.arrow_forwardflips to point leftListViewscrolls from right to left- Text aligns right by default
Most built-in widgets handle this automatically.
Directional vs absolute positioning
// WRONG: Uses absolute left/right — won't flip in RTL
Padding(
padding: const EdgeInsets.only(left: 16, right: 8),
child: ...,
)
// RIGHT: Uses start/end — flips automatically
Padding(
padding: const EdgeInsetsDirectional.only(start: 16, end: 8),
child: ...,
)
// Similarly:
Alignment.centerLeft // Absolute, won't flip
AlignmentDirectional.centerStart // Directional, flips
BorderRadius.only(topLeft: Radius.circular(12)) // Absolute
BorderRadiusDirectional.only(topStart: Radius.circular(12)) // Flips
Detecting text direction in widgets
final isRTL = Directionality.of(context) == TextDirection.rtl;
// Flip an icon manually when auto-flip isn't enough
Icon(
Icons.arrow_back,
textDirection: Directionality.of(context), // Auto-mirrors on RTL
)
// Or use Transform.scale for explicit flip
Transform.scale(
scaleX: isRTL ? -1 : 1,
child: const Icon(Icons.chevron_right),
)
Text alignment
// 'start' aligns left in LTR, right in RTL
Text(
content,
textAlign: TextAlign.start, // Correct
)
// 'left' always aligns left — avoid for body text
Text(
content,
textAlign: TextAlign.left, // Only for code/numbers where direction must be fixed
)
Testing RTL
# iOS Simulator: Settings → General → Language & Region → Region → Saudi Arabia
# Android: Settings → System → Language → Arabic
# Or in code, temporarily force RTL:
builder: (context, child) => Directionality(
textDirection: TextDirection.rtl,
child: child!,
),
Widget test:
testWidgets('layout is correct in RTL', (tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.rtl,
child: const MaterialApp(home: ProductCard()),
),
);
// Verify layout
expect(find.byType(ProductCard), findsOneWidget);
});
Number and date formatting
Numbers and dates are locale-sensitive:
import 'package:intl/intl.dart';
// Format numbers for the current locale
final formatted = NumberFormat.currency(
locale: Localizations.localeOf(context).toString(),
symbol: '\$',
).format(price);
// Arabic numerals vs Western (depends on locale)
// 'ar' locale: ١٢٣٤٥
// 'ar_EG' locale: 12345 (Egypt uses Western numerals)
// Force Western numerals:
final western = NumberFormat('#,##0.00', 'en').format(price);
Mixed direction text
When displaying mixed LTR/RTL text (e.g., English product names on an Arabic page):
Text.rich(
TextSpan(
children: [
TextSpan(
text: 'اشتري ', // Arabic: "Buy "
style: const TextStyle(fontFamily: 'Arabic'),
),
TextSpan(
text: 'iPhone 15 Pro', // English product name
style: const TextStyle(fontFamily: 'Roboto'),
),
],
),
textDirection: TextDirection.rtl,
)
Common pitfalls
Using EdgeInsets.only(left:...) throughout. Go through widgets and replace positional EdgeInsets with EdgeInsetsDirectional. A good lint rule (use_decorated_box) can catch some of these.
Absolute Alignment in Container. Alignment.centerLeft stays left in RTL. Replace with AlignmentDirectional.centerStart.
Not testing on a real RTL locale. Forcing TextDirection.rtl catches most layout issues but doesn't catch locale-specific text or number formatting bugs. Test on an Arabic or Hebrew device locale as well.
Sign in to like, dislike, or report.