This page documents the layout and container renderables in Rich: Panel, Padding, Align, Columns, and the Box character system. These classes wrap other renderables to control spacing, borders, and multi-column layout. For information about Table — which also acts as a container with borders — see Tables. For Tree and Layout, see Trees and Layout.
Rich's container renderables sit between your content and the terminal. Each one wraps a RenderableType and modifies how it is positioned or bordered in the output. They all implement __rich_console__ and __rich_measure__, plugging into the standard rendering pipeline described in Rendering Pipeline.
Container renderable diagram:
Sources: rich/panel.py1-18 rich/padding.py1-20 rich/align.py1-18 rich/columns.py1-16 rich/box.py1-12
The Box class in rich/box.py defines the full set of Unicode characters used to draw borders. A Box instance is parsed from an 8-line string where each line provides four characters for a specific region of the border.
┌─┬┐ top
│ ││ head
├─┼┤ head_row
│ ││ mid
├─┼┤ row
├─┼┤ foot_row
│ ││ foot
└─┴┘ bottom
Each character position is stored as an attribute on the Box instance. The constructor splits the 8-line string and assigns the characters to the following attribute groups:
| Region | Attributes (left, fill, divider, right) |
|---|---|
top | top_left, top, top_divider, top_right |
head | head_left, (blank), head_vertical, head_right |
head_row | head_row_left, head_row_horizontal, head_row_cross, head_row_right |
mid | mid_left, (blank), mid_vertical, mid_right |
row | row_left, row_horizontal, row_cross, row_right |
foot_row | foot_row_left, foot_row_horizontal, foot_row_cross, foot_row_right |
foot | foot_left, (blank), foot_vertical, foot_right |
bottom | bottom_left, bottom, bottom_divider, bottom_right |
Sources: rich/box.py10-60
All of these are module-level constants in rich/box.py:
| Constant | Style | ASCII? |
|---|---|---|
ASCII | +--+ style | Yes |
ASCII2 | +-++ style | Yes |
ASCII_DOUBLE_HEAD | +=++ header | Yes |
SQUARE | ┌─┬┐ style | No |
SQUARE_DOUBLE_HEAD | ╞═╪╡ header | No |
MINIMAL | Thin, inner lines only | No |
MINIMAL_HEAVY_HEAD | ╺━┿╸ header | No |
MINIMAL_DOUBLE_HEAD | ═╪ header | No |
SIMPLE | ── separator only | No |
SIMPLE_HEAD | Single separator | No |
SIMPLE_HEAVY | ━━ separator | No |
HORIZONTALS | Horizontal lines only | No |
ROUNDED | ╭─┬╮ (default Panel) | No |
HEAVY | ┏━┳┓ style | No |
HEAVY_EDGE | Heavy outer, thin inner | No |
HEAVY_HEAD | Heavy header, thin body | No |
DOUBLE | ╔═╦╗ style | No |
DOUBLE_EDGE | Double outer, thin inner | No |
MARKDOWN | ` | -` style |
Sources: rich/box.py186-421
Box.substitute() is called at render time. If options.legacy_windows is true and safe=True, certain boxes are swapped via LEGACY_WINDOWS_SUBSTITUTIONS. If options.ascii_only is true, all non-ASCII boxes are replaced with ASCII. The PLAIN_HEADED_SUBSTITUTIONS dict handles the case where show_header=False — headed box styles like HEAVY_HEAD are swapped for their plain equivalents.
Sources: rich/box.py67-93 rich/box.py405-421
| Method | Returns |
|---|---|
get_top(widths) | Top border string for given widths |
get_row(widths, level, edge) | Row divider string ("head", "row", "foot", "mid") |
get_bottom(widths) | Bottom border string |
Sources: rich/box.py95-182
Panel in rich/panel.py wraps a renderable with a border drawn using a Box style, with optional title and subtitle text embedded in the border lines.
| Parameter | Type | Default | Description |
|---|---|---|---|
renderable | RenderableType | required | Content to display inside the panel |
box | Box | ROUNDED | Border character set |
title | str or Text | None | Text embedded in the top border |
title_align | AlignMethod | "center" | "left", "center", or "right" |
subtitle | str or Text | None | Text embedded in the bottom border |
subtitle_align | AlignMethod | "center" | "left", "center", or "right" |
safe_box | bool | None | Override console's safe_box setting |
expand | bool | True | Fill full console width vs. fit to content |
style | StyleType | "none" | Style applied to both border and content background |
border_style | StyleType | "none" | Style applied to border only (layered on style) |
width | int | None | Fixed width; None = auto |
height | int | None | Fixed height; None = auto |
padding | PaddingDimensions | (0, 1) | Space between border and content (CSS-style tuple) |
highlight | bool | False | Enable auto-highlight of string content |
Panel.fit() class methodPanel.fit() is a convenience constructor that sets expand=False, making the panel shrink to its content width.
Panel.__rich_console__ performs these steps:
Padding around the renderable if self.padding has non-zero values.Box via box.substitute() for platform safety.child_width: if expand=True, it is width - 2; if expand=False, it measures the renderable's maximum width.child_width upward if the title text is wider.console.render_lines().mid_left/mid_right segments), then the bottom border (with subtitle if present).The align_text() inner function handles padding the title/subtitle with the box's top/bottom fill character to occupy the full border width at the chosen alignment.
Panel.__rich_measure__ measures both the inner renderable and the title (if present) using measure_renderables, adds the padding and the 2-character border overhead, and returns a fixed-width Measurement(width, width).
Sources: rich/panel.py141-275
Padding in rich/padding.py adds blank space around a renderable. It follows the CSS box model for specifying padding dimensions.
| Parameter | Type | Default | Description |
|---|---|---|---|
renderable | RenderableType | required | Content to pad |
pad | PaddingDimensions | (0,0,0,0) | Space amounts (see below) |
style | str or Style | "none" | Style applied to the padding space and content |
expand | bool | True | If True, fills full available width; if False, fits to content width |
PaddingDimensions formatThe pad argument accepts any of these forms, matching CSS shorthand:
| Form | Meaning |
|---|---|
int | All four sides equal |
(int,) | All four sides equal |
(top_bottom, lr) | Top+bottom and left+right pairs |
(top, right, bottom, left) | All four sides specified separately |
Padding.unpack() normalizes all these forms to a 4-tuple (top, right, bottom, left).
Padding.indent() class methodA shortcut that creates a Padding with (0, 0, 0, level) and expand=False. Used internally by Markdown and other components to produce indented blocks.
__rich_console__ renders the inner content at the reduced width (max_width - left - right), then emits top blank lines, left-padded content lines, right-padded content lines, and bottom blank lines.
Align in rich/align.py positions a renderable horizontally and/or vertically within the available space.
| Parameter | Type | Default | Description |
|---|---|---|---|
renderable | RenderableType | required | Content to align |
align | AlignMethod | "left" | Horizontal alignment: "left", "center", or "right" |
style | StyleType | None | Style applied to the padding space around content |
vertical | VerticalAlignMethod | None | Vertical alignment: "top", "middle", or "bottom" (requires height) |
pad | bool | True | If False, does not emit trailing/surrounding spaces |
width | int | None | Constrain content to this width before aligning |
height | int | None | Target height for vertical alignment |
AlignMethod and VerticalAlignMethod are Literal type aliases defined at rich/align.py13-14
These are convenience factories that set the alignment in the constructor:
| Method | Equivalent |
|---|---|
Align.left() | Align(renderable, "left", …) |
Align.center() | Align(renderable, "center", …) |
Align.right() | Align(renderable, "right", …) |
All three accept the same keyword arguments as the constructor.
__rich_console__ measures the renderable width, renders it via Constrain, then:
excess_space = options.max_width - content_width and places padding segments on the left ("right"), both sides ("center"), or right ("left").vertical is set and a vertical_height is known (from self.height or options.height), blank lines are prepended/appended to reach the target height.Sources: rich/align.py161-198
VerticalCenter (deprecated)VerticalCenter is a legacy class that only does vertical centering. It is superseded by Align with vertical="middle". Its docstring marks it as deprecated.
Columns in rich/columns.py displays a flat list of renderables arranged side-by-side in multiple columns, automatically choosing the column count to fit the terminal width.
| Parameter | Type | Default | Description |
|---|---|---|---|
renderables | Iterable | None | Initial list of renderables or strings |
padding | PaddingDimensions | (0, 1) | Padding around each cell |
width | int | None | Fixed column width; None = auto-detect |
expand | bool | False | Stretch columns to fill terminal width |
equal | bool | False | Force all columns to the same width (the widest item) |
column_first | bool | False | Fill columns top-to-bottom before moving to next column |
right_to_left | bool | False | Reverse column order within each row |
align | AlignMethod | None | Wrap each item in Align with the given method |
title | TextType | None | Optional title passed to the underlying Table.grid |
Appends a single renderable to self.renderables.
__rich_console__ builds a Table.grid() and populates it with rows. The column count is determined greedily: starting from len(renderables), it reduces the count until the total width (content widths + padding gaps) fits within options.max_width.
If width is set explicitly, the column count is computed as max_width // (width + width_padding) and each column is added with a fixed width.
If equal=True, all renderable_widths are set to the maximum value, and items are wrapped in Constrain.
If align is set, items are wrapped in Align.
column_first causes a 2D cell grid to be built and traversed column-by-column.
Sources: rich/columns.py62-171
Constrain in rich/constrain.py is a lightweight wrapper that caps the maximum render width of a renderable without adding visual elements.
It is used internally by Align and Columns. It passes options.update_width(min(self.width, options.max_width)) to the child render.
The following diagram shows how the container classes relate to each other and to underlying Rich systems:
Sources: rich/panel.py1-14 rich/align.py1-11 rich/columns.py1-13 rich/padding.py1-15 rich/constrain.py1-8
Group (render grouping)The Group class (in rich/console.py) and the @group() decorator are not in the files above, but they are directly related because Panel accepts a single RenderableType. When you need to put multiple renderables inside a Panel, wrap them in a Group:
The @group() decorator builds the same structure from a generator. See rich/docs/source/group.rst1-30
| Class | File | Wraps | Key effect |
|---|---|---|---|
Box | rich/box.py | — | Character set for drawing borders |
Panel | rich/panel.py | 1 renderable | Border drawn using Box, optional title/subtitle |
Padding | rich/padding.py | 1 renderable | Blank space around content (CSS model) |
Align | rich/align.py | 1 renderable | Horizontal and/or vertical alignment |
Columns | rich/columns.py | N renderables | Multi-column layout via Table.grid() |
Constrain | rich/constrain.py | 1 renderable | Maximum width cap, no visual elements |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.