Skip to content

Buttons & menus ​

Buttons are how users commit to an action. Loam's button family maps a familiar button suite onto Avalonia and drives every variant through control themes, so a button looks and behaves consistently wherever you place it. The whole family shares three knobs — Variant, Color (LoamColor), and Size (LoamSize) — from the Loam namespace, so once you've learned one button you've learned them all. All controls live in Loam.Controls.

csharp
using Loam;          // Variant, LoamColor, LoamSize, Icons
using Loam.Controls; // Button, IconButton, Fab, Menu, …

Mental model

Reach for a Button for anything with a text label, an IconButton when an icon alone is unambiguous, and a Fab for the one screen-level primary action. Group related buttons with ButtonGroup; collapse a list of actions behind a Menu. Everything else is styling via the three shared knobs.

Choosing a button ​

UseWhenReach for
Labelled actionThe action needs words to be clear ("Save", "Cancel")Button
Icon-only actionThe glyph is unambiguous and space is tight (toolbars, list rows)IconButton
On/off actionA single control flips between two states (favorite, mute)ToggleIconButton
Segmented choiceA small set of mutually related actions sit togetherButtonGroup
Screen primary actionOne prominent, floating "create/add" affordance per viewFab
Overflow / list of actionsMore actions than fit, or contextual commandsMenu

Variant, Color, and Size mean the same thing across all of them — see Components overview → common parameters and Theming for how they map to tokens.


Button ​

Mirrors the reference API's Button. Subclasses Avalonia's Button and adds Variant, Color, Size, FullWidth, and optional leading/trailing icons via StartIcon and EndIcon. Button templates include press ripple feedback automatically.

Use it when an action needs a text label. Pick the variant by emphasis: Filled for the primary action in a group, Outlined for secondary actions, Text for low-emphasis or inline actions.

Properties ​

PropertyTypeDefaultDescription
VariantVariantVariant.TextVisual style: Text, Filled, or Outlined.
ColorLoamColorLoamColor.DefaultSemantic color role applied to the button surface.
SizeLoamSizeLoamSize.MediumButton size: ExtraSmall, Small, Medium, Large, or ExtraLarge.
FullWidthboolfalseStretches the button to fill the available width.
StartIconstring?nullSVG path data for a leading icon.
EndIconstring?nullSVG path data for a trailing icon.
Click (event)EventHandler<RoutedEventArgs>—Inherited from Avalonia's Button; fires on activation.
Command (property)ICommand?nullInherited; executed on click.
csharp
using Loam;
using Loam.Controls;

var saveButton = new Button
{
    Content    = "Save",
    Variant    = Variant.Filled,
    Color      = LoamColor.Primary,
    Size       = LoamSize.Medium,
    StartIcon  = Icons.Material.Filled.Check,
    FullWidth  = false,
    Command    = ViewModel.SaveCommand,
};

Emphasis, not decoration

On any given surface, aim for a single Filled button (the primary action). Reaching for two or three filled buttons side by side flattens the hierarchy — make the rest Outlined or Text.


IconButton ​

Mirrors the reference API's IconButton. Inherits Button and renders a single centered glyph via the Icon property; the Variant, Color, and Size properties are inherited. Icon button templates include the same press ripple host as regular buttons.

Use it when the glyph alone is unmistakable (close, delete, edit) and horizontal space is scarce — toolbars, list-row trailing actions, app bars. Always set an accessible name (see Accessibility).

Properties ​

PropertyTypeDefaultDescription
Iconstring?nullSVG path data for the button glyph.
VariantVariantVariant.TextInherited visual style.
ColorLoamColorLoamColor.DefaultInherited semantic color.
SizeLoamSizeLoamSize.MediumInherited size.
Click (event)EventHandler<RoutedEventArgs>—Inherited from Avalonia's Button.
csharp
using Loam;
using Loam.Controls;

var deleteButton = new IconButton
{
    Icon    = Icons.Material.Filled.Delete,
    Color   = LoamColor.Error,
    Size    = LoamSize.Small,
    Variant = Variant.Outlined,
    Command = ViewModel.DeleteCommand,
};

ToggleIconButton ​

Mirrors the reference API's ToggleIconButton. Inherits IconButton; clicking flips the two-way Toggled state and swaps the displayed glyph between Icon (off) and ToggledIcon (on).

Use it when one control represents a binary state the user flips in place — favorite/unfavorite, mute/unmute, pin/unpin. Bind Toggled to your view model; the glyph and color follow the state.

Properties ​

PropertyTypeDefaultDescription
ToggledboolfalseWhether the button is in the on state. Two-way bindable.
ToggledIconstring?nullGlyph shown when Toggled is true. Falls back to Icon if null.
ToggledColorLoamColor?nullOptional glyph color while Toggled is true; unset keeps the inherited icon color.
Iconstring?nullInherited; glyph shown when not toggled.
ColorLoamColorLoamColor.DefaultInherited semantic color.
SizeLoamSizeLoamSize.MediumInherited size.
Click (event)EventHandler<RoutedEventArgs>—Fires after the toggle flip, inherited from Avalonia's Button.
csharp
using Loam;
using Loam.Controls;

var bookmark = new ToggleIconButton
{
    Icon        = Icons.Material.Filled.FavoriteBorder,
    ToggledIcon = Icons.Material.Filled.Favorite,
    Color       = LoamColor.Primary,
    ToggledColor = LoamColor.Success,
};
bookmark.Bind(ToggleIconButton.ToggledProperty,
    new Avalonia.Data.Binding(nameof(ViewModel.IsBookmarked)) { Source = ViewModel });

ButtonGroup ​

Mirrors the reference API's ButtonGroup. Lays a collection of Button instances adjacently with merged borders and shared outer corners. When OverrideChildStyles is true (the default), the group's Variant, Color, and Size are pushed onto every child.

Use it when a few related actions belong together as one unit — a segmented "Day / Week / Month" switch, or a split of related commands. For mutually exclusive selection (only one active at a time), prefer ToggleGroup, which tracks a selected value.

Properties ​

PropertyTypeDefaultDescription
ItemsObservableCollection<Button>[]The grouped buttons.
VariantVariantVariant.OutlinedShared visual style forwarded to children when OverrideChildStyles is true.
ColorLoamColorLoamColor.PrimaryShared semantic color forwarded to children.
SizeLoamSizeLoamSize.MediumShared size forwarded to children.
VerticalboolfalseStacks buttons vertically instead of horizontally.
OverrideChildStylesbooltruePushes Variant/Color/Size onto each child and manages corner radii.
csharp
using Loam;
using Loam.Controls;

var group = new ButtonGroup
{
    Variant = Variant.Outlined,
    Color   = LoamColor.Primary,
    Size    = LoamSize.Medium,
};
group.Items.Add(new Button { Content = "Day" });
group.Items.Add(new Button { Content = "Week" });
group.Items.Add(new Button { Content = "Month" });

Per-child styling

While OverrideChildStyles is true (the default) the group owns each child's Variant/Color/Size and corner radii — setting those on an individual child has no effect. Set OverrideChildStyles = false when you need a child to differ.


Fab ​

Mirrors the reference API's Fab. Inherits Button and renders as a pill-shaped, elevated, filled floating action button. An optional Label sets the button's text; StartIcon and EndIcon are inherited.

Use it when a view has one dominant action ("Add", "Compose"). Keep it to a single FAB per screen — its elevation and fill are meant to stand out, and a second one cancels that out.

Properties ​

PropertyTypeDefaultDescription
Labelstring?nullText label displayed inside the FAB. Setting this updates Content.
StartIconstring?nullInherited leading icon path data.
EndIconstring?nullInherited trailing icon path data.
ColorLoamColorLoamColor.DefaultInherited semantic color.
SizeLoamSizeLoamSize.MediumInherited size.
Click (event)EventHandler<RoutedEventArgs>—Inherited from Avalonia's Button.
csharp
using Loam;
using Loam.Controls;

var fab = new Fab
{
    Label     = "Add item",
    StartIcon = Icons.Material.Filled.Add,
    Color     = LoamColor.Primary,
    Command   = ViewModel.AddCommand,
};

Mirrors the reference API's Menu. Inherits Button for its trigger appearance; clicking opens an Avalonia Flyout containing the Items list. Each row is represented by a MenuItem plain-object. Disabled menu triggers do not open, disabled rows are skipped by keyboard navigation, Escape closes the popup, and Up/Down move through enabled rows.

Use it when there are more actions than fit comfortably, or the actions are contextual/secondary. For navigation between views, use NavMenu instead.

PropertyTypeDefaultDescription
ItemsObservableCollection<MenuItem>[]The dropdown rows.
VariantVariantVariant.TextInherited trigger button style.
ColorLoamColorLoamColor.DefaultInherited trigger button color.
SizeLoamSizeLoamSize.MediumInherited trigger button size.
MenuWidthdouble180Minimum popup surface width.
CloseOnItemClickbooltrueWhether choosing an enabled row closes the popup.
OpenMenu() / CloseMenu()methods—Public imperative open/close hooks.

MenuItem is a plain CLR class (not a Control); add instances directly to Menu.Items.

PropertyTypeDefaultDescription
Textstring?nullLabel displayed in the dropdown row.
Iconstring?nullOptional leading icon path data for the row.
OnClickAction?nullCallback invoked when the row is selected.
ShortcutTextstring?nullOptional trailing shortcut hint.
IsDividerboolfalseRenders this entry as a divider row.
IsEnabledbooltrueDisabled rows are visible but not focusable or activatable.
csharp
using Loam;
using Loam.Controls;

var menu = new Menu
{
    Content = "Actions",
    Variant = Variant.Outlined,
    Color   = LoamColor.Primary,
    MenuWidth = 220,
};
menu.Items.Add(new MenuItem
{
    Text    = "Edit",
    Icon    = Icons.Material.Filled.Edit,
    ShortcutText = "E",
    OnClick = () => ViewModel.EditCommand.Execute(null),
});
menu.Items.Add(new MenuItem { IsDivider = true });
menu.Items.Add(new MenuItem
{
    Text    = "Delete",
    Icon    = Icons.Material.Filled.Delete,
    IsEnabled = ViewModel.CanDelete,
    OnClick = () => ViewModel.DeleteCommand.Execute(null),
});

Recipe: a row toolbar ​

A common layout — a labelled primary action, a grouped set, and an overflow menu — composed from the family above. Everything is plain C#; lay the pieces out with a StackPanel (see Surfaces & layout).

csharp
using Avalonia.Controls;
using Avalonia.Layout;
using Loam;
using Loam.Controls;

var toolbar = new StackPanel
{
    Orientation = Orientation.Horizontal,
    Spacing = 8,
    Children =
    {
        new Button
        {
            Content   = "New",
            Variant   = Variant.Filled,
            Color     = LoamColor.Primary,
            StartIcon = Icons.Material.Filled.Add,
            Command   = ViewModel.NewCommand,
        },
        new ButtonGroup
        {
            Variant = Variant.Outlined,
            Color   = LoamColor.Default,
            Items =
            {
                new Button { Content = "Day" },
                new Button { Content = "Week" },
                new Button { Content = "Month" },
            },
        },
        new IconButton
        {
            Icon    = Icons.Material.Filled.ContentCopy,
            Variant = Variant.Text,
            Command = ViewModel.CopyCommand,
        },
    },
};

Accessibility & keyboard ​

Every button in this family subclasses Avalonia's Button, so it is keyboard-operable out of the box:

  • Focus — buttons are in the tab order and show a focus adorner; Tab / Shift+Tab move between them.
  • Activation — Space and Enter invoke Click / Command. ToggleIconButton flips Toggled on activation.
  • Disabled — setting IsEnabled = false removes the control from the tab order and blocks activation.
  • Menu — the trigger opens on activation; inside the popup ↑/↓ move through enabled rows, disabled rows are skipped, and Esc closes it.

Name your icon-only buttons

An IconButton or ToggleIconButton has no text for assistive technology to read. Give it an accessible name so screen readers announce its purpose:

csharp
using Avalonia.Automation;

var delete = new IconButton { Icon = Icons.Material.Filled.Delete, Color = LoamColor.Error };
AutomationProperties.SetName(delete, "Delete");

See also ​

MIT Licensed · Independent Avalonia controls.