diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 1b8e37d374..d919fa900e 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -236,4 +236,9 @@ public string Name
- PRs must not introduce new compiler warnings (fix warnings in files you modify)
- Title format: `Fixes #issue. Terse description`
-- Update `Examples/UICatalog` scenarios when adding user-visible features
\ No newline at end of file
+- Update `Examples/UICatalog` scenarios when adding user-visible features
+
+## Documentation Style
+
+- In reference/how-to/API docs, write instructions as `To [goal], [imperative action].`
+- Avoid `When/If you want/need to ...` unless describing a real condition.
diff --git a/AGENTS.md b/AGENTS.md
index 960350b3d0..4759b28b60 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -118,6 +118,7 @@ dotnet test --project Tests/UnitTestsParallelizable --no-build --filter-method "
7. **Backing fields** - Place immediately before their property
8. **Early return / guard clauses (CRITICAL)** - ALWAYS prefer guard clauses over nested `if`/`else`. Invert the condition, return/continue early, keep happy path at lowest indentation. This applies to methods, lambdas, loops — everywhere. See [early-return.md](/.claude/rules/early-return.md) for detailed examples.
9. **One type per file** - Public and internal types each get their own file
+10. **Docs instruction style** - In reference/how-to/API docs, write `To [goal], [imperative action].` Avoid `When/If you want/need to ...` unless describing a real condition.
## Detailed Coding Rules
@@ -518,6 +519,5 @@ See `.claude/cookbook/` for common UI patterns:
-
diff --git a/CLAUDE.md b/CLAUDE.md
index 45df41e576..599c0b24ad 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -127,6 +127,7 @@ See `Tests/README.md` for the full list of test projects (including `Integration
8. **Unused lambda params** - use `_`: `(_, _) => { }`
9. **Early return / guard clauses** - ALWAYS invert conditions and return/continue early. Never wrap the happy path in a conditional. Applies to methods, lambdas, and loops. See `.claude/rules/early-return.md`.
10. **One type per file** - Public and internal types each get their own file
+11. **Docs instruction style** - In reference/how-to/API docs, write `To [goal], [imperative action].` Avoid `When/If you want/need to ...` unless describing a real condition.
## Testing
diff --git a/Terminal.Gui/ViewBase/Layout/Dim.cs b/Terminal.Gui/ViewBase/Layout/Dim.cs
index c1994193ed..1f941d2e7c 100644
--- a/Terminal.Gui/ViewBase/Layout/Dim.cs
+++ b/Terminal.Gui/ViewBase/Layout/Dim.cs
@@ -3,17 +3,19 @@
namespace Terminal.Gui.ViewBase;
///
+/// Describes a declarative, responsive dimension for a .
+/// is the type of and .
+/// Integer values are implicitly convertible to an absolute .
+///
+///
///
-/// A Dim object describes the dimensions of a . Dim is the type of the
-/// and properties of .
+/// To make a view's size respond to the available space, its content, or the size and position of other views
+/// rather than using a fixed number of cells, use .
///
///
-/// Integer values are implicitly convertible to an absolute . These objects are created using
-/// the static methods described below. The objects can be combined with the addition and
-/// subtraction operators.
+/// To define responsive sizing in Terminal.Gui, describe the relationship that should be maintained and let the
+/// layout engine resolve the final whenever layout runs.
///
-///
-///
///
///
///
@@ -109,8 +111,8 @@ public abstract record Dim : IEqualityOperators
///
/// SubViews that use do not contribute to the auto-sizing calculation unless
/// is specified. Without it, a SubView will
- /// receive a size of 0. Use with a minimumContentDim to ensure
- /// the SubView contributes a minimum size.
+ /// receive a size of 0. To ensure the SubView contributes a minimum size, use
+ /// with a minimumContentDim.
///
///
///
@@ -141,9 +143,9 @@ public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim? minimumCont
///
///
/// If the SuperView uses , a SubView does not
- /// contribute to the auto-sizing calculation and will receive a size of 0. Use
- /// with a minimumContentDim or with
- /// a to parameter to ensure the SubView contributes to auto-sizing.
+ /// contribute to the auto-sizing calculation and will receive a size of 0. To make the SubView contribute to
+ /// auto-sizing, use with a minimumContentDim or
+ /// with a to parameter.
/// See the Dim.Auto Deep Dive for details.
///
///
@@ -162,9 +164,9 @@ public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim? minimumCont
///
///
/// If the SuperView uses , a SubView does not
- /// contribute to the auto-sizing calculation and will receive a size of 0. Use
- /// with a minimumContentDim or with
- /// a to parameter to ensure the SubView contributes to auto-sizing.
+ /// contribute to the auto-sizing calculation and will receive a size of 0. To make the SubView contribute to
+ /// auto-sizing, use with a minimumContentDim or
+ /// with a to parameter.
/// See the Dim.Auto Deep Dive for details.
///
///
diff --git a/Terminal.Gui/ViewBase/Layout/Pos.cs b/Terminal.Gui/ViewBase/Layout/Pos.cs
index de79dfe562..8b93cb8b20 100644
--- a/Terminal.Gui/ViewBase/Layout/Pos.cs
+++ b/Terminal.Gui/ViewBase/Layout/Pos.cs
@@ -1,22 +1,28 @@
namespace Terminal.Gui.ViewBase;
///
-/// Describes the position of a which can be an absolute value, a percentage, centered, or
-/// relative to the ending dimension. Integer values are implicitly convertible to an absolute . These
-/// objects are created using the static methods Percent, AnchorEnd, and Center. The objects can be
-/// combined with the addition and subtraction operators.
+/// Describes a declarative, responsive position for a .
+/// A can be absolute, percentage-based, centered, anchored to an edge, or relative to another
+/// . Integer values are implicitly convertible to an absolute .
///
///
-/// Use the objects on the X or Y properties of a view to control the position.
///
-/// These can be used to set the absolute position, when merely assigning an integer value (via the implicit
-/// integer to conversion), and they can be combined to produce more useful layouts, like:
-/// Pos.Center - 3, which would shift the position of the 3 characters to the left after
-/// centering for example.
+/// To describe where a view should be, relative to its , its available space, or its
+/// sibling views, use with and .
///
///
-/// Reference coordinates of another view by using the methods Left(View), Right(View), Bottom(View), Top(View).
-/// The X(View) and Y(View) are aliases to Left(View) and Top(View) respectively.
+/// To define responsive horizontal and vertical placement in Terminal.Gui, describe the relationship that should
+/// be maintained and let the layout engine resolve the final whenever layout runs.
+///
+///
+/// values can be combined to produce more useful layouts, such as
+/// Pos.Center () - 3, which shifts the resolved position of the 3 cells earlier on
+/// the axis after centering.
+///
+///
+/// To reference coordinates of another view, use , ,
+/// , and . and are
+/// aliases to and respectively.
///
///
///
diff --git a/Terminal.Gui/ViewBase/View.Layout.cs b/Terminal.Gui/ViewBase/View.Layout.cs
index ab9b441d47..e6cb655723 100644
--- a/Terminal.Gui/ViewBase/View.Layout.cs
+++ b/Terminal.Gui/ViewBase/View.Layout.cs
@@ -17,7 +17,9 @@ public partial class View // Layout APIs
private Rectangle? _frame;
- /// Gets or sets the absolute location and dimension of the view.
+ ///
+ /// Gets or sets the resolved location and dimension of the view.
+ ///
///
/// The rectangle describing absolute location and dimension of the view, in coordinates relative to the
/// 's Content, which is bound by .
@@ -28,6 +30,11 @@ public partial class View // Layout APIs
///
///
///
+ /// is typically the output of Terminal.Gui's responsive layout system. To describe layout,
+ /// use , , , and . To inspect the
+ /// resolved result, read after layout has resolved those relationships.
+ ///
+ ///
/// Frame is relative to the 's Content, which is bound by
/// .
///
@@ -207,7 +214,9 @@ private void PosDimSet ()
private Pos _x = Pos.Absolute (0);
- /// Gets or sets the X position for the view (the column).
+ ///
+ /// Gets or sets the declarative horizontal position for the view.
+ ///
/// The object representing the X position.
///
///
@@ -215,6 +224,10 @@ private void PosDimSet ()
///
///
///
+ /// To express responsive relationships such as "center this view", "anchor it to the end", or "place it to
+ /// the right of another view", use with .
+ ///
+ ///
/// The position is relative to the 's Content, which is bound by
/// .
///
@@ -230,7 +243,7 @@ private void PosDimSet ()
///
/// Changing this property will cause to be updated.
///
- /// The default value is Pos.At (0).
+ /// The default value is Pos.Absolute (0).
///
public Pos X
{
@@ -252,7 +265,9 @@ public Pos X
private Pos _y = Pos.Absolute (0);
- /// Gets or sets the Y position for the view (the row).
+ ///
+ /// Gets or sets the declarative vertical position for the view.
+ ///
/// The object representing the Y position.
///
///
@@ -260,6 +275,10 @@ public Pos X
///
///
///
+ /// To express responsive relationships such as "center this view", "anchor it to the bottom", or "place it
+ /// below another view", use with .
+ ///
+ ///
/// The position is relative to the 's Content, which is bound by
/// .
///
@@ -275,7 +294,7 @@ public Pos X
///
/// Changing this property will cause to be updated.
///
- /// The default value is Pos.At (0).
+ /// The default value is Pos.Absolute (0).
///
public Pos Y
{
@@ -296,7 +315,9 @@ public Pos Y
private Dim _height = Dim.Absolute (0);
- /// Gets or sets the height dimension of the view.
+ ///
+ /// Gets or sets the declarative height for the view.
+ ///
/// The object representing the height of the view (the number of rows).
///
///
@@ -304,6 +325,10 @@ public Pos Y
///
///
///
+ /// To express responsive sizing such as filling remaining space, using a percentage of the available height,
+ /// or growing to fit content with Dim.Auto (), use with .
+ ///
+ ///
/// The dimension is relative to the 's Content, which is bound by
/// .
///
@@ -383,7 +408,9 @@ protected virtual void OnHeightChanged (ValueChangedEventArgs args) { }
private Dim _width = Dim.Absolute (0);
- /// Gets or sets the width dimension of the view.
+ ///
+ /// Gets or sets the declarative width for the view.
+ ///
/// The object representing the width of the view (the number of columns).
///
///
@@ -391,6 +418,10 @@ protected virtual void OnHeightChanged (ValueChangedEventArgs args) { }
///
///
///
+ /// To express responsive sizing such as filling remaining space, using a percentage of the available width,
+ /// or growing to fit content with Dim.Auto (), use with .
+ ///
+ ///
/// The dimension is relative to the 's Content, which is bound by
///
/// .
@@ -507,7 +538,7 @@ internal static bool Layout (IEnumerable views, Size contentSize)
}
///
- /// Performs layout of the view and its subviews within the specified content size.
+ /// Resolves the view's declarative layout and then lays out its subviews within the specified content size.
///
///
///
@@ -515,8 +546,12 @@ internal static bool Layout (IEnumerable views, Size contentSize)
///
///
///
- /// This method is intended to be called by the layout engine to
- /// prepare the view for layout and is exposed as a public API primarily for testing purposes.
+ /// This method turns responsive and expressions into an absolute
+ /// , then recursively lays out SubViews.
+ ///
+ ///
+ /// This method is intended to be called by the layout engine to prepare the view for layout and is exposed as
+ /// a public API primarily for testing purposes.
///
///
///
@@ -537,8 +572,8 @@ public bool Layout (Size contentSize)
}
///
- /// Performs layout of the view and its subviews using the content size of either the or
- /// .
+ /// Resolves the view's declarative layout and then lays out its subviews using the content size of either the
+ /// or .
///
///
///
@@ -546,21 +581,27 @@ public bool Layout (Size contentSize)
///
///
///
- /// This method is intended to be called by the layout engine to
- /// prepare the view for layout and is exposed as a public API primarily for testing purposes.
+ /// To force a responsive layout pass after changing , , , or
+ /// , call this overload.
+ ///
+ ///
+ /// This method is intended to be called by the layout engine to prepare the view for layout and is exposed as
+ /// a public API primarily for testing purposes.
///
///
/// If the view could not be laid out (typically because dependency was not ready).
public bool Layout () => Layout (GetContainerSize ());
///
- /// Sets the position and size of this view, relative to the SuperView's ContentSize (nominally the same as
- /// this.SuperView.GetContentSize ()) based on the values of , ,
- /// ,
- /// and .
+ /// Resolves this view's declarative layout into a concrete position and size, relative to the SuperView's
+ /// content size, based on , , , and .
///
///
///
+ /// This method is the core step that turns responsive and expressions
+ /// into the view's absolute .
+ ///
+ ///
/// If , , , or are
/// absolute, they will be updated to reflect the new size and position of the view. Otherwise, they
/// are left unchanged.
diff --git a/docfx/docs/layout.md b/docfx/docs/layout.md
index 25173b2892..1e3e7243cd 100644
--- a/docfx/docs/layout.md
+++ b/docfx/docs/layout.md
@@ -1,6 +1,8 @@
# Layout
-Terminal.Gui provides a rich system for how [View](View.md) objects are laid out relative to each other. The layout system also defines how coordinates are specified.
+Terminal.Gui layout is declarative and responsive. To define layout, describe how a [View](View.md) should relate to its `SuperView`, its content, and sibling views. To inspect the resolved result, read the final `Frame` after layout runs, including after terminal resizes.
+
+To apply a mental model similar to responsive web or React-style layouts, declare relationships such as "center this", "fill the remaining space", "stay 1 cell to the right of that view", or "use 50% of the available width", and let the layout engine resolve the actual coordinates.
See [View Deep Dive](View.md), [Arrangement Deep Dive](arrangement.md), [Scrolling Deep Dive](scrolling.md), and [Drawing Deep Dive](drawing.md) for more.
@@ -11,6 +13,7 @@ See [View Deep Dive](View.md), [Arrangement Deep Dive](arrangement.md), [Scrolli
- [Composition](#composition)
- [The Content Area](#the-content-area)
- [The Viewport](#the-viewport)
+- [Responsive Mental Model](#responsive-mental-model)
- [Layout Engine](#layout-engine)
- [Pos](#pos)
- [Dim](#dim)
@@ -96,17 +99,65 @@ The flags are organized into categories:
- `HasHorizontalScrollBar` - Enables the built-in `HorizontalScrollBar` with .Auto behavior (automatically shown when content exceeds viewport)
- `HasScrollBars` - Combines both vertical and horizontal scrollbar flags
+## Responsive Mental Model
+
+To reason about Terminal.Gui layout, think of it as a small responsive layout language for TUIs:
+
+- `X` and `Y` answer **where should this view start?**
+- `Width` and `Height` answer **how much space should it take?**
+- `Pos` expresses location relationships.
+- `Dim` expresses size relationships.
+- `Frame` is the resolved result after layout runs.
+
+To build adaptive UIs, work with `Pos` and `Dim`, not `Frame`.
+
+Common patterns include:
+
+- Pinning to an edge with `Pos.AnchorEnd ()`
+- Centering with `Pos.Center ()`
+- Following another view with `Pos.Right (otherView)` or `Pos.Bottom (otherView)`
+- Taking a percentage of the available space with `Dim.Percent (...)`
+- Filling leftover space with `Dim.Fill ()` or `Dim.Fill (to: otherView)`
+- Growing to content with `Dim.Auto ()`
+
+When the terminal size changes, or when the size of a `SuperView` or referenced view changes, layout runs again and these relationships are resolved into a new `Frame`. This is what makes Terminal.Gui layouts responsive.
+
## Layout Engine
-Terminal.Gui provides a rich system for how views are laid out relative to each other. The position of a view is set by setting the `X` and `Y` properties, which are of time . The size is set via `Width` and `Height`, which are of type .
+The primary layout API is:
+
+- `X` and `Y` for position, using
+- `Width` and `Height` for size, using
+
+These values are relative to the `SuperView`'s content area, not the screen.
+
+```cs
+Label nameLabel = new () { Text = "Name:" };
+Button okButton = new () { Text = "OK", X = Pos.AnchorEnd () };
+TextField nameField = new ()
+{
+ X = Pos.Right (nameLabel) + 1,
+ Y = Pos.Top (nameLabel),
+ Width = Dim.Fill (to: okButton)
+};
+```
+
+In this example:
+
+- `nameLabel` keeps its content-based width
+- `okButton` stays anchored to the end of the line
+- `nameField` stretches and shrinks between them
-The layout system uses virtual properties for categorization without type checking: `ReferencesOtherViews()`, `DependsOnSuperViewContentSize`, `CanContributeToAutoSizing`, `GetMinimumContribution()`, `IsFixed`, and `RequiresTargetLayout`. This enables extensibility.
+If the terminal or `SuperView` grows or shrinks, the same declarations are re-evaluated and the final `Frame` values change automatically.
+
+For advanced scenarios and custom layout primitives, the layout system also exposes virtual categorization hooks such as `ReferencesOtherViews()`, `DependsOnSuperViewContentSize`, `CanContributeToAutoSizing`, `GetMinimumContribution()`, `IsFixed`, and `RequiresTargetLayout`.
```cs
-var label1 = new Label () { X = 1, Y = 2, Width = 3, Height = 4, Title = "Absolute")
+Label absoluteLabel = new () { X = 1, Y = 2, Width = 12, Height = 1, Text = "Absolute" };
-var label2 = new Label () {
- Title = "Computed",
+Label responsiveLabel = new ()
+{
+ Text = "Responsive",
X = Pos.Right (otherView),
Y = Pos.Center (),
Width = Dim.Fill (),
@@ -116,26 +167,26 @@ var label2 = new Label () {
### Pos
- is the type of `View.X` and `View.Y` and supports the following sub-types:
+ is the type of `View.X` and `View.Y`. To make a view's position respond to available space or other views instead of using a fixed coordinate, use it.
-* Absolute position, by passing an integer - `Pos.Absolute()`.
-* Percentage of the parent's view size - `Pos.Percent()`
-* Anchored from the end of the dimension - `Pos.AnchorEnd()`
-* Centered, using `Pos.Center()`
-* The `Pos.Left()`, `Pos.Right()`, `Pos.Top()`, and `Pos.Bottom()` tracks the position of another view.
-* Aligned (left, right, center, etc...) with other views - `Pos.Align()`
-* An arbitrary function - `Pos.Func()`
+* Absolute position, by passing an integer - `Pos.Absolute ()`
+* Percentage of the `SuperView` size - `Pos.Percent ()`
+* Anchored from the end of the dimension - `Pos.AnchorEnd ()`
+* Centered - `Pos.Center ()`
+* Tracking another view - `Pos.Left ()`, `Pos.Right ()`, `Pos.Top ()`, `Pos.Bottom ()`
+* Aligning as a group - `Pos.Align ()`
+* Computing from a function - `Pos.Func ()`
All coordinates are relative to the SuperView's content area.
- values can be combined using addition or subtraction:
+ values can be combined using addition or subtraction, making it easy to express offsets in a responsive layout:
```cs
// Set the X coordinate to 10 characters left from the center
view.X = Pos.Center () - 10;
view.Y = Pos.Percent (20);
-anotherView.X = AnchorEnd (10);
+anotherView.X = Pos.AnchorEnd (10);
anotherView.Width = 9;
myView.X = Pos.X (view);
@@ -143,25 +194,28 @@ myView.Y = Pos.Bottom (anotherView) + 5;
```
### Dim
- is the type of `View.Width` and `View.Height` and supports the following sub-types:
+ is the type of `View.Width` and `View.Height`. To make size respond to content, terminal size, or sibling views instead of using a fixed number of cells, use it.
+
+* Automatic size based on the view's content - `Dim.Auto ()` - See [Dim.Auto Deep Dive](dimauto.md)
+* Absolute size, by passing an integer - `Dim.Absolute ()`
+* Percentage of the `SuperView` content area - `Dim.Percent ()`
+* Fill the remaining space - `Dim.Fill ()`
+* Fill up to another view - `Dim.Fill (to: otherView)`
+* Track another view's size - `Dim.Width ()`, `Dim.Height ()`
+* Compute from a function - `Dim.Func ()`
-* Automatic size based on the View's content (either SubViews or Text) - `Dim.Auto()` - See [Dim.Auto Deep Dive](dimauto.md).
-* Absolute size, by passing an integer - `Dim.Absolute()`.
-* Percentage of the SuperView's Content Area - `Dim.Percent()`.
-* Fill to the end of the SuperView's Content Area - `Dim.Fill()`. **Note:** `Dim.Fill` does not contribute to a SuperView's `Dim.Auto()` sizing unless `minimumContentDim` is specified. See [Dim.Auto Deep Dive](dimauto.md) for details.
-* Reference the Width or Height of another view - `Dim.Width()`, `Dim.Height()`.
-* An arbitrary function - `Dim.Func()`.
+`Dim.Fill ()` is especially useful for responsive forms and panes. **Note:** `Dim.Fill` does not contribute to a `SuperView`'s `Dim.Auto ()` sizing unless `minimumContentDim` is specified. See [Dim.Auto Deep Dive](dimauto.md) for details.
All dimensions are relative to the SuperView's content area.
-Like, , objects of type can be combined using addition or subtraction, like this:
+Like , objects of type can be combined using addition or subtraction:
```cs
// Set the Width to be 10 characters less than filling
// the remaining portion of the screen
view.Width = Dim.Fill () - 10;
-view.Height = Dim.Percent(20) - 1;
+view.Height = Dim.Percent (20) - 1;
anotherView.Height = Dim.Height (view) + 1;
```
@@ -190,11 +244,11 @@ classDiagram
## How To
-This section provides solutions to common layout scenarios.
+To solve common layout scenarios, use this section.
### Stretch a View Between Fixed Elements
-**Scenario:** A label on the left, a text field that stretches to fill available space, and a button anchored to the right:
+**Scenario:** A label on the left, a text field that stretches to fill available space, and a button anchored to the right. This is a classic responsive form row:
```
[label][ stretching text field ][button]
@@ -206,11 +260,14 @@ Button btn = new () { Text = "_OK", X = Pos.AnchorEnd () };
TextField textField = new ()
{
X = Pos.Right (label) + 1,
- Width = Dim.Func (() => btn.Frame.X - label.Frame.Width - 1)
+ Width = Dim.Fill (to: btn)
};
superView.Add (label, textField, btn);
```
+The text field expands and contracts automatically as the available width changes.
+Here `to: btn` names the `Dim.Fill` parameter that tells the text field where its fill should stop.
+
### Align Multiple Views (Like Dialog Buttons)
**Scenario:** Align buttons horizontally using `Pos.Align()`, as does:
@@ -250,4 +307,3 @@ Window popup = new ()
```
The key insight is `maximumContentDim` subtracts the adornments thickness from 100% to ensure the view (including its , , and ) never exceeds the SuperView's bounds.
-
diff --git a/llms.txt b/llms.txt
index 790b368876..2dbdf395e0 100644
--- a/llms.txt
+++ b/llms.txt
@@ -344,6 +344,7 @@ public sealed class FormWindow : Runnable
3. **Instance-based app** — `Application.Create ().Init ()` returns `IApplication`
4. **`App!.RequestStop ()`** — Not `Application.RequestStop ()`
5. **SubView/SuperView** — Never "child"/"parent"/"container" in docs/discussion
+6. **Docs instruction style** — In reference/how-to/API docs, write `To [goal], [imperative action].` Avoid `When/If you want/need to ...` unless describing a real condition.
### Code Style (Library Contributors Only)