RTL (Right-to-Left) Layout Support in Flutter: Complete Guide
Master RTL layout support in Flutter for Arabic, Hebrew, Persian, and other RTL languages. Learn text direction, mirrored layouts, and bidirectional text.
Published on • September 19, 2026
AI Assistant

RTL (Right-to-Left) Layout Support in Flutter: Complete Guide
Flutter provides built-in support for right-to-left (RTL) languages like Arabic, Hebrew, Persian, and Urdu. With proper configuration, your app automatically mirrors its layout when an RTL locale is selected, ensuring a native experience for billions of RTL users.
Why RTL Support Matters
Over 1.5 billion people speak RTL languages. Without proper RTL support:
- Text alignment is wrong
- Navigation direction is reversed
- Icons and controls appear in wrong positions
- Layout breaks for RTL users
Flutter’s RTL support is automatic when properly configured.
How RTL Works in Flutter
Flutter uses the Directionality widget to determine text direction:
Directionality(
textDirection: TextDirection.rtl, // or TextDirection.ltr
child: YourWidget(),
)
When you use MaterialApp with proper localization, Flutter automatically sets the correct direction based on the selected locale.
Automatic RTL Configuration
Basic Setup
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, // Handles RTL
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''), // English (LTR)
Locale('ar', ''), // Arabic (RTL)
Locale('he', ''), // Hebrew (RTL)
Locale('fa', ''), // Persian (RTL)
],
home: const HomeScreen(),
);
}
}
Layout Mirroring
Automatic Mirroring with Directionality
Most Flutter widgets automatically mirror in RTL mode:
// This row automatically reverses in RTL mode
Row(
children: [
Icon(Icons.arrow_back), // Becomes arrow_forward in RTL
Text('Back'),
const Spacer(),
Icon(Icons.arrow_forward), // Becomes arrow_back in RTL
],
)
// This list tile automatically mirrors
ListTile(
leading: Icon(Icons.chevron_right), // Becomes chevron_left in RTL
title: Text('Settings'),
)
Manual Directionality Control
For custom layouts that need RTL support:
class CustomCard extends StatelessWidget {
const CustomCard({super.key});
@override
Widget build(BuildContext context) {
final textDirection = Directionality.of(context);
return Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Leading element (reverses in RTL)
const Icon(Icons.star, color: Colors.amber),
const SizedBox(width: 8),
// Content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Rating'),
const Text('4.5 out of 5'),
],
),
),
// Trailing element (reverses in RTL)
Icon(
textDirection == TextDirection.rtl
? Icons.chevron_left
: Icons.chevron_right,
),
],
),
);
}
}
RTL-Aware Widgets
Padding and Margin
// RTL-aware padding
Padding(
padding: EdgeInsetsDirectional.only(
start: 16, // Left in LTR, Right in RTL
end: 8, // Right in LTR, Left in RTL
),
child: Text('RTL-aware padding'),
)
// RTL-aware margin
Container(
margin: const EdgeInsetsDirectional.only(
top: 8,
bottom: 8,
start: 16,
end: 8,
),
child: Text('RTL-aware margin'),
)
Positioning
PositionedDirectional(
start: 16, // Left in LTR, Right in RTL
top: 16,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
)
Alignment
Align(
alignment: AlignmentDirectional.centerStart,
child: Text('Aligned to start'),
)
// Or use the convenience constants
Align(
alignment: AlignmentDirectional.centerStart, // Start edge
child: Text('Start-aligned'),
)
Align(
alignment: AlignmentDirectional.centerEnd, // End edge
child: Text('End-aligned'),
)
Bidirectional Text
Mixing LTR and RTL Text
Flutter handles bidirectional text automatically:
Text(
'This is English text mixed with نص عربي and more English',
textDirection: TextDirection.ltr,
)
// Flutter correctly renders the mixed text
Explicit Text Direction
// Force text direction for specific text
Text(
'مرحبا بالعالم',
textDirection: TextDirection.rtl,
)
// Or use BidiFormatter for automatic detection
import 'package:intl/bidi.dart';
Text(
Bidi.stripHtmlIfNeeded('مرحبا Hello World'),
)
Testing RTL Support
Visual Testing
testWidgets('renders correctly in RTL', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('ar', ''),
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: MyWidget(),
),
);
await expectLater(
find.byType(MyWidget),
matchesGoldenFile('golden/rtl_layout.png'),
);
});
Directionality Testing
testWidgets('correct text direction', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('ar', ''),
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: MyWidget(),
),
);
final direction = Directionality.of(
tester.element(find.byType(MyWidget)),
);
expect(direction, TextDirection.rtl);
});
Common Patterns
Navigation Icons
class NavigationIcon extends StatelessWidget {
const NavigationIcon({super.key});
@override
Widget build(BuildContext context) {
final isRTL = Directionality.of(context) == TextDirection.rtl;
return Icon(
isRTL ? Icons.arrow_back : Icons.arrow_forward,
);
}
}
Drawer and Navigation
// Drawer automatically appears on correct side
Scaffold(
drawer: const Drawer(
child: MenuItems(),
),
// In RTL: drawer opens from right
// In LTR: drawer opens from left
)
Custom Scroll Views
// Scrollbar position adjusts automatically
ListView(
children: items.map((item) => ListTile(
title: Text(item.name),
trailing: const Icon(Icons.chevron_right),
)).toList(),
)
Best Practices
- Always use
EdgeInsetsDirectionalinstead ofEdgeInsetsfor start/end spacing - Use
PositionedDirectionalfor positioned elements - Let Flutter mirror icons automatically — don’t manually flip them
- Test with both LTR and RTL locales
- Use
TextDirectiononly when you need explicit control - Handle bidirectional text — let Flutter’s text engine handle it
Resources
RTL support is essential for building truly global Flutter apps. With Flutter’s built-in directionality support, you can create experiences that feel native for RTL users without significant code changes.