FlexPanel

Tip

This guide covers details for the FlexPanel control. If you are just getting started with the Uno Toolkit UI Library, please see our general getting started page to make sure you have the correct setup in place.

Summary

FlexPanel arranges its children using CSS Flexbox semantics. Layout is computed by a vendored C# port of Meta's Yoga engine, so sizing, wrapping and distribution follow the CSS specification rather than an approximation of it. That port — and the Panel adapter this control is adapted from — comes from Microsoft's Reactor project. Both are MIT; see THIRD-PARTY-NOTICES.md.

For task-oriented recipes, see the FlexPanel walkthrough.

C#

public partial class FlexPanel : Panel

XAML

xmlns:utu="using:Uno.Toolkit.UI"
...

<utu:FlexPanel Direction="Row"
               Wrap="Wrap"
               AlignItems="Center"
               ColumnGap="8"
               RowGap="8"
               Padding="16,8">
    <TextBlock Text="MyApp" utu:FlexPanel.Shrink="0" />
    <Border utu:FlexPanel.Grow="1" />
    <Button Content="Settings" />
</utu:FlexPanel>

FlexPanel vs AutoLayout: which do I want?

Both arrange children along an axis, and they are independent controls — neither replaces the other.

Use When
FlexPanel You are thinking in CSS terms: flex-grow / flex-shrink / flex-basis distribution, wrapping onto multiple lines, justify-content / align-items, gaps that act as a floor. Also when porting a web layout, where matching flexbox exactly matters.
AutoLayout You are reproducing a Figma auto-layout frame and want its semantics — including Figma-specific concepts such as independent (absolutely positioned) children, reverse Z-index, and negative spacing.

Two concrete capability differences worth knowing before you choose:

  • FlexPanel wraps onto multiple lines; AutoLayout does not.
  • AutoLayout supports negative Spacing (for deliberately overlapping items such as stacked avatars). FlexPanel cannot: the engine clamps a negative gap to 0. Use a negative child Margin instead, which is supported.

Properties

Container properties

Property Type Default CSS equivalent
Direction FlexDirection Row flex-direction
Wrap FlexWrap NoWrap flex-wrap
JustifyContent FlexJustify FlexStart justify-content
AlignItems FlexAlign Stretch align-items
AlignContent FlexAlign FlexStart align-content
ColumnGap double 0 column-gap
RowGap double 0 row-gap
Padding Thickness 0 padding

Attached properties

Set these on the children of a FlexPanel.

Property Type Default CSS equivalent
FlexPanel.Grow double 0 flex-grow
FlexPanel.Shrink double 1 flex-shrink
FlexPanel.Basis double NaN (= auto) flex-basis (points only)
FlexPanel.FlexMinWidth double NaN (= no floor) min-width
FlexPanel.FlexMinHeight double NaN (= no floor) min-height
FlexPanel.AlignSelf FlexAlign Auto align-self
FlexPanel.Position FlexPositionType Relative position
FlexPanel.Left / .Top / .Right / .Bottom double NaN inset properties

FlexMinWidth and FlexMinHeight carry the Flex prefix deliberately. They would otherwise sit next to FrameworkElement.MinWidth / MinHeight on the same element while meaning something different: the framework properties force Measure to return at least X, whereas these clamp the flex-resolved slot to at least X.

Properties that participate without an attached property

A child's Margin, Width, Height, MinWidth / MaxWidth, MinHeight / MaxHeight and Visibility are read directly:

Child property Effect
Margin Mapped to the item's margin edges.
Width / Height Mapped to a definite item size; NaN means auto.
MinWidth / MaxWidth, MinHeight / MaxHeight Clamp the item's slot, so grow and shrink stop at them. A MinWidth combines with FlexMinWidth (the larger wins).
Visibility="Collapsed" Mapped to display: none — the child contributes no size and no gap slot.

Which FlexAlign members apply where

As in CSS, AlignItems, AlignContent and AlignSelf share one keyword set (FlexAlign), so not every member is meaningful on every property. Every member of FlexDirection, FlexWrap, FlexJustify and FlexPositionType has an effect.

Property Meaningful members
JustifyContent FlexStart, Center, FlexEnd, SpaceBetween, SpaceAround, SpaceEvenly
AlignItems Stretch, FlexStart, Center, FlexEnd, Baseline
AlignContent FlexStart, Center, FlexEnd, Stretch, SpaceBetween, SpaceAround, SpaceEvenly
AlignSelf Auto plus everything valid for AlignItems

Basis vs Width

This is the most common surprise when coming from WinUI. On the main axis, Basis is the flex base size and Width is not:

<!-- Arranges 400 wide, not 200: Grow resolves the slot and Width is not the flex base size. -->
<utu:FlexPanel Width="400">
    <Border Width="200" utu:FlexPanel.Basis="100" utu:FlexPanel.Grow="1" />
</utu:FlexPanel>

Equal columns need Basis="0"

Grow="1" alone distributes only the leftover space, so items with different content stay different sizes. Equal columns are the CSS flex: 1 1 0 shorthand — both Grow and Basis:

<!-- Three columns of exactly the same width, whatever their content. -->
<utu:FlexPanel ColumnGap="8">
    <Border utu:FlexPanel.Grow="1" utu:FlexPanel.Basis="0" />
    <Border utu:FlexPanel.Grow="1" utu:FlexPanel.Basis="0" />
    <Border utu:FlexPanel.Grow="1" utu:FlexPanel.Basis="0" />
</utu:FlexPanel>

Minimum size

By default a child can shrink all the way to 0, as in Yoga and React Native. This is a deliberate difference from CSS, where §4.5 floors a flex item at its min-content size (for text, its longest word). WinUI has no way to ask an element for its min-content size, so that floor cannot be computed.

To keep a child from being crushed:

  • set FlexPanel.Shrink="0" to keep it at its natural size, or
  • set FlexPanel.FlexMinWidth / FlexPanel.FlexMinHeight to an explicit floor.

FlexMinWidth always clamps the width and FlexMinHeight always clamps the height, whatever the Direction.

Nesting FlexPanels

On its own, a FlexPanel fills the width it is offered, like a block-level CSS flex container. Set HorizontalAlignment to anything other than Stretch to size it to its content instead.

A FlexPanel placed directly inside another FlexPanel is a flex item, so it follows the flex-item rules:

  • In a row, it starts at its content width. Give it FlexPanel.Grow="1" to take the remaining space.
  • In a column, it fills the column with the default AlignItems="Stretch", and hugs its content with Center, FlexStart or FlexEnd (or the matching FlexPanel.AlignSelf).

When another panel sits between the two (a Border, StackPanel or Grid), the inner FlexPanel fills whatever width that panel hands it. Set HorizontalAlignment="Left" on it when it should hug its content.

Right-to-left

Set FlowDirection="RightToLeft" (inherited from FrameworkElement), as with any other panel. The engine always lays out left-to-right and the platform mirrors the whole panel, so the main axis starts on the right.

Because the mirroring is visual, the Left / Right insets of an absolutely positioned child swap sides too, the same way Canvas.Left does. CSS treats left / right as physical edges instead.

Layout rounding

UseLayoutRounding (inherited from UIElement) controls whether the engine snaps results to the pixel grid:

  • true (default) — the engine rounds using the current XamlRoot.RasterizationScale.
  • false — the engine emits unrounded values and only the platform's own rounding applies.

Set it to false if you see sub-pixel drift from double-rounding on a particular target.

Limitations

  • No border or corner radius. FlexPanel derives from Panel, which exposes only Background. Wrap it in a Border if you need one.
  • No order. CSS order is not supported and is not planned: the underlying engine does not implement it. Reorder the children instead.
  • Negative gaps clamp to 0. Use a negative child Margin for overlap.
  • Basis is points only. Percentage values are not supported.
  • Not yet surfaced: MaxWidth/MaxHeight, AspectRatio, Overflow, BoxSizing, the flex shorthand, and CSS Grid. Each is additive and may be added later.

Samples

The FlexPanel page under Controls in the sample app walks through each property with a labelled example. Its Open the interactive playground button opens a full-screen surface where every container and per-child property is driven live, including a UseLayoutRounding toggle, a FlowDirection toggle, a 200-child stress case, and a readout of each child's arranged rectangle.