details/Accordion and Tree Disclosure to Avalonia Expander and TreeView<details> to Expander)Primary APIs:
Expander (Header, IsExpanded, ExpandDirection, ContentTransition)TreeView, TreeViewItemSelectionMode, SelectedItem, SelectionChangedReference docs:
13-html-css-navigation-tabs-sidebars-breadcrumbs-and-routing-patterns.md16-html-css-accessibility-semantics-and-motion-preference-mapping.mdcontrols/expander.mdcontrols/tree-view.md| HTML/CSS idiom | Avalonia mapping |
|---|---|
<details open> |
Expander IsExpanded="True" |
<summary> |
Expander Header |
| accordion with one panel open | coordinated Expander IsExpanded view-model state |
<ul role="tree"> + nested <li> |
TreeView with nested TreeViewItem or hierarchical templates |
aria-expanded node state |
TreeViewItem IsExpanded |
<details> to Expander)HTML/CSS:
<details open class="section">
<summary>Project Settings</summary>
<div class="body">Build, signing, and deployment options.</div>
</details>
.section {
border: 1px solid #d8deea;
border-radius: 10px;
padding: 8px 12px;
}
.section > summary {
cursor: pointer;
font-weight: 600;
}
Avalonia:
<Expander Header="Project Settings"
IsExpanded="True"
ExpandDirection="Down">
<Border Padding="8" Classes="panel-body">
<TextBlock Text="Build, signing, and deployment options." />
</Border>
</Expander>
HTML/CSS accordion behavior is typically JS-controlled. In Avalonia, drive each Expander.IsExpanded from a single selected key.
<StackPanel Spacing="8">
<Expander Header="General"
IsExpanded="{CompiledBinding IsGeneralOpen}">
<TextBlock Text="General project settings." />
</Expander>
<Expander Header="Security"
IsExpanded="{CompiledBinding IsSecurityOpen}">
<TextBlock Text="Certificates and secrets." />
</Expander>
<Expander Header="Deploy"
IsExpanded="{CompiledBinding IsDeployOpen}">
<TextBlock Text="Publishing channels." />
</Expander>
</StackPanel>
HTML/CSS tree baseline:
<ul role="tree" class="nav-tree">
<li role="treeitem" aria-expanded="true">
Docs
<ul role="group">
<li role="treeitem">Getting Started</li>
<li role="treeitem">API</li>
</ul>
</li>
<li role="treeitem">Samples</li>
</ul>
Avalonia tree equivalent:
<TreeView SelectionMode="Single"
SelectedItem="{CompiledBinding SelectedNode, Mode=TwoWay}">
<TreeViewItem Header="Docs" IsExpanded="True">
<TreeViewItem Header="Getting Started" />
<TreeViewItem Header="API" />
</TreeViewItem>
<TreeViewItem Header="Samples" />
</TreeView>
<section class="workspace">
<aside>
<ul role="tree" class="nav-tree">
<li role="treeitem" aria-expanded="true">Settings
<ul role="group">
<li role="treeitem">General</li>
<li role="treeitem">Security</li>
</ul>
</li>
<li role="treeitem">Logs</li>
</ul>
</aside>
<main>
<details open>
<summary>General</summary>
<div>General options panel...</div>
</details>
</main>
</section>
.workspace {
display: grid;
grid-template-columns: 260px 1fr;
gap: 12px;
}
.nav-tree { list-style: none; padding-inline-start: 12px; }
<Grid ColumnDefinitions="260,*" ColumnSpacing="12">
<TreeView Grid.Column="0"
SelectionMode="Single"
SelectedItem="{CompiledBinding SelectedNode, Mode=TwoWay}">
<TreeViewItem Header="Settings" IsExpanded="True">
<TreeViewItem Header="General" />
<TreeViewItem Header="Security" />
</TreeViewItem>
<TreeViewItem Header="Logs" />
</TreeView>
<StackPanel Grid.Column="1" Spacing="8">
<Expander Header="General"
IsExpanded="{CompiledBinding IsGeneralOpen}">
<Border Padding="8">
<TextBlock Text="General options panel..." />
</Border>
</Expander>
</StackPanel>
</Grid>
using Avalonia.Controls;
var root = new Grid
{
ColumnDefinitions = ColumnDefinitions.Parse("260,*"),
ColumnSpacing = 12
};
var tree = new TreeView
{
SelectionMode = SelectionMode.Single
};
var settings = new TreeViewItem { Header = "Settings", IsExpanded = true };
settings.Items.Add(new TreeViewItem { Header = "General" });
settings.Items.Add(new TreeViewItem { Header = "Security" });
tree.Items.Add(settings);
tree.Items.Add(new TreeViewItem { Header = "Logs" });
var generalExpander = new Expander
{
Header = "General",
IsExpanded = true,
Content = new Border
{
Padding = new Avalonia.Thickness(8),
Child = new TextBlock { Text = "General options panel..." }
}
};
var content = new StackPanel { Spacing = 8 };
content.Children.Add(generalExpander);
Grid.SetColumn(tree, 0);
Grid.SetColumn(content, 1);
root.Children.Add(tree);
root.Children.Add(content);
Dispatcher.UIThread.IsExpanded is not reset by state sync code.SelectedSection) and derive each IsExpanded from it.SelectedItem binding is TwoWay and SelectionMode matches expected interaction.