FlowDirection Mapping to AvaloniaPrimary APIs:
FlowDirection on Visual (LeftToRight, RightToLeft)TextBlock.TextAlignment (use logical alignment where possible)Grid.SetColumn, Grid.SetRow, spans) for explicit mirroringTextLayout and FormattedText flow-direction parametersReference docs:
16-html-css-accessibility-semantics-and-motion-preference-mapping.md19-focus-and-keyboard-navigation.md59-media-colors-brushes-and-formatted-text-practical-usage.md| Web idiom | Avalonia mapping |
|---|---|
<html dir="rtl"> or direction: rtl on app root |
set root FlowDirection="RightToLeft" |
direction: ltr on subtree |
set subtree FlowDirection="LeftToRight" |
text-align: start |
TextAlignment="Start" |
per-component :dir(rtl) styling |
direction class (rtl/ltr) plus style selectors |
| custom canvas/text drawing with RTL | pass FlowDirection.RightToLeft to TextLayout/FormattedText |
<html dir="rtl">
<body>
<div class="shell">
<aside class="nav">...</aside>
<main class="content">
<h1 class="start-aligned">طلبات اليوم</h1>
<p dir="ltr" class="code">Order #A-1042</p>
</main>
</div>
</body>
</html>
:root[dir="rtl"] .shell {
direction: rtl;
}
.start-aligned {
text-align: start;
}
.rtl-only:dir(rtl) {
padding-inline-start: 16px;
}
XAML root pattern:
<Grid FlowDirection="{CompiledBinding AppFlowDirection}">
<StackPanel Spacing="8">
<TextBlock Text="{CompiledBinding PageTitle}" TextAlignment="Start" />
<TextBlock Text="{CompiledBinding Subtitle}" TextAlignment="Start" />
<!-- Force LTR for product codes/emails even in RTL pages -->
<Border FlowDirection="LeftToRight" Padding="8">
<TextBlock Text="{CompiledBinding ProductCode}" TextAlignment="Start" />
</Border>
</StackPanel>
</Grid>
C# direction source:
using Avalonia.Media;
public FlowDirection AppFlowDirection { get; set; } = FlowDirection.RightToLeft;
For critical chrome regions (navigation rail, utility pane, primary content), mirror placement explicitly so behavior is deterministic across controls.
using Avalonia.Controls;
using Avalonia.Media;
static void ApplyShellDirection(Grid shell, Control navRail, Control mainContent, FlowDirection flowDirection)
{
shell.FlowDirection = flowDirection;
var rtl = flowDirection == FlowDirection.RightToLeft;
Grid.SetColumn(navRail, rtl ? 1 : 0);
Grid.SetColumn(mainContent, rtl ? 0 : 1);
}
This is a practical equivalent of swapping CSS grid areas/tracks between LTR and RTL variants.
Mixed scripts (Arabic/Hebrew + codes, SKUs, numbers) are usually best modeled as separate text runs/controls with local direction overrides.
<StackPanel FlowDirection="RightToLeft" Spacing="4">
<TextBlock Text="طلبات اليوم" TextAlignment="Start" />
<TextBlock FlowDirection="LeftToRight"
Text="Order #A-1042"
TextAlignment="Start" />
</StackPanel>
For custom drawing paths, always pass explicit direction to text layout objects.
using Avalonia.Media;
var textLayout = new TextLayout(
text: "طلبات اليوم",
typeface: new Typeface("Segoe UI"),
fontSize: 14,
foreground: Brushes.Black,
textAlignment: TextAlignment.Start,
flowDirection: FlowDirection.RightToLeft,
maxWidth: 360);
FormattedText supports the same explicit flow-direction input for lower-level draw scenarios.
using Avalonia.Controls;
using Avalonia.Media;
var shell = new Grid
{
ColumnDefinitions = ColumnDefinitions.Parse("220,*"),
FlowDirection = FlowDirection.RightToLeft
};
var navRail = new Border
{
Child = new TextBlock { Text = "Navigation" }
};
var mainContent = new StackPanel
{
Spacing = 8,
Children =
{
new TextBlock { Text = "طلبات اليوم", TextAlignment = TextAlignment.Start },
new Border
{
FlowDirection = FlowDirection.LeftToRight,
Child = new TextBlock { Text = "Order #A-1042", TextAlignment = TextAlignment.Start }
}
}
};
Grid.SetColumn(navRail, 1);
Grid.SetColumn(mainContent, 0);
shell.Children.Add(navRail);
shell.Children.Add(mainContent);
XYFocus) in critical layouts.FlowDirection.Grid.SetColumn) instead of relying on incidental defaults.