Table of Contents

Layout

Terminal.Gui layout is declarative and responsive. To define layout, describe how a View 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, Arrangement Deep Dive, Scrolling Deep Dive, and Drawing Deep Dive for more.

Table of Contents


Lexicon & Taxonomy

Term Meaning
Adornment Lightweight objects (IAdornment implementations) that define the Thicknesses separating the Frame from the Viewport. There are three Adornments: Margin, Border, and Padding. Each can lazily create an AdornmentView for rendering and SubView support via GetOrCreateView(). Adornments are not part of the View's content and are not clipped by the View's ClipArea.
Application-Relative The dimensions and characteristics of the application. Because only full-screen apps are currently supported, @Terminal.Gui.Application is effectively the same as Screen from a layout perspective. Application-Relative currently means an origin (0, 0) at the top-left corner of the terminal. @Terminal.Gui.Application.Top is a View with a top-left corner fixed at the Application.Relative coordinate of (0, 0) and is the size of Screen.
Border The Adornment that resides in the inside of the Margin. The Border is where a visual border (drawn using line-drawing glyphs) and the @Terminal.Gui.View.Title are drawn, and where the user can interact with the mouse/keyboard to adjust the Views' Arrangement.
Content Area Describes the View's total content. The location of the content is always (0, 0) and the size is set by @Terminal.Gui.View.SetContentSize* and defaults to the size of the Viewport. If the content size is larger than the Viewport, scrolling is enabled.
Content-Relative A rectangle, with an origin of (0, 0) and size, defined by @Terminal.Gui.View.GetContentSize*, where the View's content exists. Content-Relative means a coordinate is relative to the top-left corner of the content, which is always (0,0). @Terminal.Gui.View.ContentToScreen* and @Terminal.Gui.View.ScreenToContent* are helper methods for translating coordinates.
Frame A Rectangle that defines the location and size of the @Terminal.Gui.View. The coordinates are relative to the SuperView of the View (or, in the case of Application.Top, the console size). Controlled by @Terminal.Gui.View.X, @Terminal.Gui.View.Y, @Terminal.Gui.View.Width, and @Terminal.Gui.View.Height.
Frame-Relative The @Terminal.Gui.View.Frame property of a View is a rectangle that describes the current location and size of the view relative to the Superview's content area. Frame-Relative means a coordinate is relative to the top-left corner of the View in question. @Terminal.Gui.View.FrameToScreen* and @Terminal.Gui.View.ScreenToFrame* are helper methods for translating coordinates.
Margin The outermost Adornment. The outside of the margin is a rectangle the same size as the Frame. By default Margin is {0,0,0,0}. When made thicker, Margins are visually transparent and transparent to mouse events by default.
Overlapped/Overlapping Refers to a form Layout where SubViews of a View are visually arranged such that their Frames overlap. In Overlap view arrangements there is a Z-axis (Z-order) in addition to the X and Y dimension.
Padding The Adornment resides in the inside of the Border and outside of the Viewport. Padding is {0, 0, 0, 0} by default. Padding is not part of the View's content and is not clipped by the View's Clip. When enabled, scroll bars reside within Padding.
Screen-Relative Describes the dimensions and characteristics of the underlying terminal. Currently Terminal.Gui only supports applications that run "full-screen", meaning they fill the entire terminal when running. Screen-Relative means an origin (0, 0) at the top-left corner of the terminal. @Terminal.Gui.ConsoleDriver implementations operate exclusively on Screen-Relative coordinates.
Thickness A smart record struct describing a rectangle where each of the four sides can have a width. Valid width values are >= 0. The inner area of a Thickness is the sum of the widths of the four sides minus the size of the rectangle.
Tiled/Tiling Refer to a form of Views that are visually arranged such that they abut each other and do not overlap. In a Tiled view arrangement, Z-ordering only comes into play when a developer intentionally causes views to be aligned such that they overlap.
Viewport The Rectangle that describes the portion of the View's Content Area that is currently visible to the user. If size of the Content Area is larger than the Viewport, scrolling is enabled and the Viewport location determines which portion of the content is visible.
Viewport-Relative A Content-Relative rectangle representing the subset of the View's content that is visible to the user: @Terminal.Gui.View.Viewport. Viewport-Relative means a coordinate that is bound by (0,0) and the size of the inner-rectangle of the View's Padding. The View drawing primitives (e.g. View.Move) take Viewport-Relative coordinates.

Arrangement Modes

See Arrangement Deep Dive for more.

Composition

View Composition Diagram

classDiagram
    class View {
        +Frame: Rectangle
        +Margin: AdornmentImpl - outermost
        +Border: AdornmentImpl - border lines and Title
        +Padding: AdornmentImpl - innermost - Scrollbars
        +Viewport: Rectangle describing portal into ContentArea
        +ContentArea: Rectangle with Location always 0,0
        +GetContentSize(): Size
        +SetContentSize(Size)
    }

    class AdornmentImpl {
        +Thickness: Thickness
    }

    class Thickness {
        +Top: int
        +Right: int
        +Bottom: int
        +Left: int
    }

    class Rectangle {
        +Location: Point
        +Size: Size
    }

    View --> AdornmentImpl : has
    AdornmentImpl --> Thickness : has
    View --> Rectangle : has

    note for View "Frame defines location and size relative to SuperView"
    note for AdornmentImpl "Separates Frame from Viewport"
    note for Rectangle "Defines location and size"

The diagram above shows the structure of a View's composition:

  1. Frame: The outermost rectangle defining the View's location and size
  2. Margin: Separates the View from other SubViews
  3. Border: Contains visual border and title
  4. Padding: Offsets the Viewport from the Border
  5. Viewport: The visible portion of the Content Area
  6. Content Area: Where the View's content is drawn (shown larger than Viewport to illustrate scrolling)

Each layer is defined by a Thickness that specifies the width of each side (top, right, bottom, left). The Content Area is shown as a separate container that the Viewport "looks into" - this illustrates how scrolling works. In this example, the Viewport is positioned at (5,5) relative to the Content Area, showing how scrolling works.

The Content Area

Content Area refers to the rectangle with a location of 0,0 with the size returned by GetContentSize().

The content area is the area where the view's content is drawn. Content can be any combination of the Text property, SubViews, and other content drawn by the View. The GetContentSize() method gets the size of the content area of the view.

The Content Area size tracks the size of the Viewport by default. If the content size is set via SetContentSize(), the content area is the provided size. If the content size is larger than the Viewport, scrolling is enabled.

The Viewport

The Viewport is a rectangle describing the portion of the Content Area that is visible to the user. It is a "portal" into the content. The Viewport.Location is relative to the top-left corner of the inner rectangle of View.Padding. If Viewport.Size is the same as View.GetContentSize(), Viewport.Location will be 0,0.

To enable scrolling call View.SetContentSize() and then set Viewport.Location to positive values. Making Viewport.Location positive moves the Viewport down and to the right in the content.

See the Scrolling Deep Dive for details on how to enable scrolling.

Viewport Settings

The ViewportSettings property controls how the Viewport is constrained using ViewportSettingsFlags. By default, ViewportSettings is None, which provides sensible constraints for typical scrolling scenarios.

Default Behavior (No Flags Set)

With no flags set, the Viewport is constrained as follows:

  • No negative scrolling: Viewport.X and Viewport.Y cannot go below 0. The user cannot scroll above or to the left of the content origin.
  • Content fills the viewport: The Viewport is clamped so that Viewport.X + Viewport.Width <= ContentSize.Width and Viewport.Y + Viewport.Height <= ContentSize.Height. This prevents blank space from appearing when scrolling - the content always fills the visible area.
  • Last row/column always visible: Even if trying to scroll past the end of content, at least the last row and last column remain visible.

Flag Categories

The flags are organized into categories:

Negative Location Flags - Allow scrolling before the content origin (0,0):

  • AllowNegativeX - Permits Viewport.X < 0 (scroll left of content)
  • AllowNegativeY - Permits Viewport.Y < 0 (scroll above content)
  • AllowNegativeLocation - Combines both X and Y

Greater Than Content Flags - Allow scrolling past the last row/column:

  • AllowXGreaterThanContentWidth - Permits Viewport.X >= ContentSize.Width
  • AllowYGreaterThanContentHeight - Permits Viewport.Y >= ContentSize.Height
  • AllowLocationGreaterThanContentSize - Combines both X and Y

Blank Space Flags - Allow blank space to appear when scrolling:

  • AllowXPlusWidthGreaterThanContentWidth - Permits Viewport.X + Viewport.Width > ContentSize.Width (blank space on right)
  • AllowYPlusHeightGreaterThanContentHeight - Permits Viewport.Y + Viewport.Height > ContentSize.Height (blank space on bottom)
  • AllowLocationPlusSizeGreaterThanContentSize - Combines both X and Y

Conditional Negative Flags - Allow negative scrolling only when viewport is larger than content:

  • AllowNegativeXWhenWidthGreaterThanContentWidth - Useful for centering content smaller than the view
  • AllowNegativeYWhenHeightGreaterThanContentHeight - Useful for centering content smaller than the view
  • AllowNegativeLocationWhenSizeGreaterThanContentSize - Combines both X and Y

Drawing Flags - Control clipping and clearing behavior:

  • ClipContentOnly - Clips drawing to the visible content area instead of the entire Viewport
  • ClearContentOnly - Clears only the visible content area (requires ClipContentOnly)
  • Transparent - The view does not clear its background when drawing
  • TransparentMouse - Mouse events pass through areas not occupied by SubViews

ScrollBar Flags - Enable built-in scrollbars:

  • HasVerticalScrollBar - Enables the built-in VerticalScrollBar with ScrollBarVisibilityMode.Auto behavior (automatically shown when content exceeds viewport)
  • HasHorizontalScrollBar - Enables the built-in HorizontalScrollBar with ScrollBarVisibilityMode.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

The primary layout API is:

  • X and Y for position, using Pos
  • Width and Height for size, using Dim

These values are relative to the SuperView's content area, not the screen.

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

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.

Label absoluteLabel = new () { X = 1, Y = 2, Width = 12, Height = 1, Text = "Absolute" };

Label responsiveLabel = new ()
{
    Text = "Responsive",
    X = Pos.Right (otherView),
    Y = Pos.Center (),
    Width = Dim.Fill (),
    Height = Dim.Percent (50)
};

Pos

Pos 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 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 Pos coordinates are relative to the SuperView's content area.

Pos values can be combined using addition or subtraction, making it easy to express offsets in a responsive layout:

// Set the X coordinate to 10 characters left from the center
view.X = Pos.Center () - 10;
view.Y = Pos.Percent (20);

anotherView.X = Pos.AnchorEnd (10);
anotherView.Width = 9;

myView.X = Pos.X (view);
myView.Y = Pos.Bottom (anotherView) + 5;

Dim

Dim 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
  • 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 ()

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 for details.

All Dim dimensions are relative to the SuperView's content area.

Like Pos, objects of type Dim can be combined using addition or subtraction:

// 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;

anotherView.Height = Dim.Height (view) + 1;
classDiagram
    class View ["View — location and size relative to SuperView"]
    class Frame ["Frame — Rectangle"]
    class Viewport ["Viewport — visible portion of Content Area"]
    class Margin ["Margin — where Shadows live"]
    class Border ["Border — Title and Arrangement controls"]
    class Padding ["Padding — where ScrollBars live"]
    class AdornmentImpl ["AdornmentImpl — lightweight settings"]
    class Thickness ["Thickness — each side has a width"]

    View --> Frame
    View --> Viewport
    View --> Margin : has
    View --> Border : has
    View --> Padding : has
    Margin --|> AdornmentImpl
    Border --|> AdornmentImpl
    Padding --|> AdornmentImpl
    AdornmentImpl --> Thickness : has

How To

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. This is a classic responsive form row:

[label][    stretching text field    ][button]
Label label = new () { Text = "_Name:" };
Button btn = new () { Text = "_OK", X = Pos.AnchorEnd () };
TextField textField = new ()
{
    X = Pos.Right (label) + 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 Dialog does:

Button cancelBtn = new ()
{
    Text = "_Cancel",
    X = Pos.Align (Alignment.End)
};
Button okBtn = new ()
{
    Text = "_OK",
    X = Pos.Align (Alignment.End)
};
superView.Add (cancelBtn, okBtn);

The Pos.Align method supports different alignments (Start, Center, End, Fill) and can add spacing between items via AlignmentModes.

Center with Auto-Sizing and Constraints (Like Dialog)

Scenario: A centered view that auto-sizes to its content, with minimum and maximum constraints that account for adornments (Border, Margin, Padding). This is how Dialog positions and sizes itself:

Window popup = new ()
{
    X = Pos.Center (),
    Y = Pos.Center (),
    Width = Dim.Auto (
        minimumContentDim: 20,  // Minimum width
        maximumContentDim: Dim.Percent (100) - Dim.Func (_ => popup.GetAdornmentsThickness ().Horizontal)),
    Height = Dim.Auto (
        minimumContentDim: 5,   // Minimum height
        maximumContentDim: Dim.Percent (100) - Dim.Func (_ => popup.GetAdornmentsThickness ().Vertical))
};

The key insight is maximumContentDim subtracts the adornments thickness from 100% to ensure the view (including its Border, Margin, and Padding) never exceeds the SuperView's bounds.