Skip to content

Commit 74a4fdd

Browse files
committed
more words
1 parent 0a2710f commit 74a4fdd

File tree

5 files changed

+113
-36
lines changed

5 files changed

+113
-36
lines changed

CHANGELOG.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8-
### Unreleased
9-
10-
## Added
11-
12-
- Added `CenterMiddle` container
13-
148
## [3.5.0] - 2025-06-20
159

1610
### Changed

docs/examples/how-to/containers08.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ class ContainerApp(App):
2424
"""
2525

2626
def compose(self) -> ComposeResult:
27-
yield Box("Box 1")
28-
with Center(classes="with-border"):
27+
yield Box("Box 1") # (1)!
28+
with Center(classes="with-border"): # (2)!
2929
yield Box("Box 2")
30-
with Right(classes="with-border"):
30+
with Right(classes="with-border"): # (3)!
3131
yield Box("Box 3")
3232

3333

docs/examples/how-to/containers09.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from textual.app import App, ComposeResult
2-
from textual.containers import HorizontalGroup, Middle
2+
from textual.containers import Middle
33
from textual.widgets import Placeholder
44

55

@@ -24,11 +24,10 @@ class ContainerApp(App):
2424
"""
2525

2626
def compose(self) -> ComposeResult:
27-
with HorizontalGroup():
28-
yield Box("Box 1")
29-
with Middle(classes="with-border"):
30-
yield Box("Box 2")
31-
yield Box("Box 3")
27+
with Middle(classes="with-border"): # (1)!
28+
yield Box("Box 1.")
29+
yield Box("Box 2.")
30+
yield Box("Box 3.")
3231

3332

3433
if __name__ == "__main__":

docs/how-to/work-with-containers.md

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
# Work with containers
1+
# Save time with Textual containers
2+
3+
Textual's [containers][textual.containers] provide a convenient way of arranging your widgets. Let's look at them in a little detail.
4+
5+
!!! info "Are you in the right place?"
6+
7+
We are talking about Textual container widgets here. Not to be confused with [containerization](https://en.wikipedia.org/wiki/Containerization_(computing))—which is something else entirely!
28

3-
Textual's [containers][textual.containers] provide a convenient way of arranging your widgets. Let's look at them in a little detail!
49

510
## What are containers?
611

@@ -30,7 +35,7 @@ Before I describe some of the other containers, I would like to show how contain
3035
The following is the actual source of the `Horizontal` widget:
3136

3237
```python
33-
class Horizontal(Widget, inherit_bindings=False):
38+
class Horizontal(Widget):
3439
"""An expanding container with horizontal layout and no scrollbars."""
3540

3641
DEFAULT_CSS = """
@@ -47,8 +52,6 @@ That's it!
4752
A simple widget with a few preset styles.
4853
The other containers are just as simple.
4954

50-
You can customize the container with TCSS in the same way as other widgets.
51-
5255
## Horizontal and Vertical
5356

5457
We've seen the `Horizontal` container in action.
@@ -69,6 +72,10 @@ And here's the output:
6972

7073
Three boxes, vertically stacked.
7174

75+
!!! tip "Styling layout"
76+
77+
You can set the layout of a compound widget with the [layout](../styles/layout.md) rule.
78+
7279
### Size behavior
7380

7481
Something to keep in mind when using `Horizontal` or `Vertical` is that they will consume the remaining space in the screen. Let's look at an example to illustrate that.
@@ -100,7 +107,7 @@ And here's the result:
100107
```
101108

102109
Two horizontal containers divide the remaining screen space in two.
103-
If you were to add another horizontal it would divide the screen space in to thirds--and so on.
110+
If you were to add another horizontal it would divide the screen space in to thirds—and so on.
104111

105112
This makes `Horizontal` and `Vertical` excellent for designing the macro layout of your app's interface, but not for making tightly packed rows or columns. For that you need the *group* containers which I'll cover next.
106113

@@ -132,7 +139,7 @@ We can see that the widgets are arranged horizontally as before, but they only u
132139
Something to watch out for regarding the previous containers we have discussed, is that they don't scroll by default.
133140
Let's see what happens if we add more boxes than could fit on the screen.
134141

135-
In the following example, we will add boxes:
142+
In the following example, we will add 10 boxes:
136143

137144
```python hl_lines="28 29"
138145
--8<-- "docs/examples/how-to/containers06.py"
@@ -161,7 +168,84 @@ Here's the output:
161168

162169
We now have a scrollbar we can click and drag to see all the boxes.
163170

164-
!!! tip "Automatic scrollbars"
171+
!!! tip "Automatic scrollbars"
172+
173+
You can also implement automatic scrollbars with the [overflow](../styles/overflow.md) style.
174+
175+
176+
## Center, Right, and Middle
177+
178+
The [Center][textual.containers.Center], [Right][textual.containers.Right], and [Middle][textual.containers.Middle] containers are handy for setting the alignment of select widgets.
179+
180+
First lets look at `Center` and `Right` which align their children on the horizontal axis (there is no `Left` container, as this is the default).
181+
182+
Here's an example:
183+
184+
```python hl_lines="2 28 30"
185+
--8<-- "docs/examples/how-to/containers08.py"
186+
```
187+
188+
1. The default is to align widgets to the left.
189+
2. Align the child to the center.
190+
3. Align the child to the right edge.
191+
192+
Here's the output:
193+
194+
```{.textual path="docs/examples/how-to/containers08.py"}
195+
```
196+
197+
Note how `Center` and `Right` expand to fill the horizontal dimension, but are only as tall as they need to be.
198+
199+
!!! tip "Alignment in TCSS"
200+
201+
You can set alignment in TCSS with the [align](../styles/align.md) rule.
202+
203+
The [Middle][textual.containers.Middle] container aligns its children to the center of the *vertical* axis.
204+
Let's look at an example.
205+
The following code aligns three boxes on the vertical axis:
206+
207+
```python hl_lines="2 27"
208+
--8<-- "docs/examples/how-to/containers09.py"
209+
```
210+
211+
1. Align children to the center of the vertical axis.
212+
213+
Here's the output:
214+
215+
```{.textual path="docs/examples/how-to/containers09.py"}
216+
```
217+
218+
Note how the container expands on the vertical axis, but fits on the horizontal axis.
219+
220+
## Other containers
221+
222+
This how-to covers the most common widgets, but isn't exhausted.
223+
Be sure to visit the [container reference][textual.containers] for the full list.
224+
There may be new containers added in future versions of Textual.
225+
226+
## Custom containers
227+
228+
The builtin [containers][textual.containers] cover a number of common layout patterns, but are unlikely to cover every possible requirement.
229+
Fortunately, creating your own is easy.
230+
Just like the builtin containers, you can create a container by extending Widget and adding little TCSS.
231+
232+
Here's a template for a custom container:
233+
234+
```python
235+
class MyContainer(Widget):
236+
"""My custom container."""
237+
DEFAULT_CSS = """
238+
MyContainer {
239+
# Your rules here
240+
}
241+
"""
242+
```
243+
244+
## Summary
165245

166-
You can implement automatic scrollbars with the [overflow](../styles/overflow.md) style.
167-
246+
- Containers are compound widgets with preset styles for arranging their children.
247+
- [`Horizontal`][textual.containers.Horizontal] and [`Vertical`][textual.containers.Vertical] containers stretch to fill available space.
248+
- [`HorizontalGroup`][textual.containers.HorizontalGroup] and [`VerticalGroup`][textual.containers.VerticalGroup] fit to the height of their contents.
249+
- [`HorizontalScroll`][textual.containers.HorizontalScroll] and [`VerticalScroll`][textual.containers.VerticalScroll] add automatic scrollbars.
250+
- [`Center`][textual.containers.Center], [`Right`][textual.containers.Right], and [`Middle`][textual.containers.Middle] set alignment.
251+
- Custom containers are trivial to create.

src/textual/containers.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Container(Widget):
2929
"""
3030

3131

32-
class ScrollableContainer(Widget, can_focus=True, inherit_bindings=False):
32+
class ScrollableContainer(Widget, can_focus=True):
3333
"""A scrollable container with vertical layout, and auto scrollbars on both axis."""
3434

3535
# We don't typically want to maximize scrollable containers,
@@ -118,7 +118,7 @@ def allow_maximize(self) -> bool:
118118
return self.can_maximize
119119

120120

121-
class Vertical(Widget, inherit_bindings=False):
121+
class Vertical(Widget):
122122
"""An expanding container with vertical layout and no scrollbars."""
123123

124124
DEFAULT_CSS = """
@@ -131,7 +131,7 @@ class Vertical(Widget, inherit_bindings=False):
131131
"""
132132

133133

134-
class VerticalGroup(Widget, inherit_bindings=False):
134+
class VerticalGroup(Widget):
135135
"""A non-expanding container with vertical layout and no scrollbars."""
136136

137137
DEFAULT_CSS = """
@@ -156,7 +156,7 @@ class VerticalScroll(ScrollableContainer):
156156
"""
157157

158158

159-
class Horizontal(Widget, inherit_bindings=False):
159+
class Horizontal(Widget):
160160
"""An expanding container with horizontal layout and no scrollbars."""
161161

162162
DEFAULT_CSS = """
@@ -169,7 +169,7 @@ class Horizontal(Widget, inherit_bindings=False):
169169
"""
170170

171171

172-
class HorizontalGroup(Widget, inherit_bindings=False):
172+
class HorizontalGroup(Widget):
173173
"""A non-expanding container with horizontal layout and no scrollbars."""
174174

175175
DEFAULT_CSS = """
@@ -194,7 +194,7 @@ class HorizontalScroll(ScrollableContainer):
194194
"""
195195

196196

197-
class Center(Widget, inherit_bindings=False):
197+
class Center(Widget):
198198
"""A container which aligns children on the X axis."""
199199

200200
DEFAULT_CSS = """
@@ -206,7 +206,7 @@ class Center(Widget, inherit_bindings=False):
206206
"""
207207

208208

209-
class Right(Widget, inherit_bindings=False):
209+
class Right(Widget):
210210
"""A container which aligns children on the X axis."""
211211

212212
DEFAULT_CSS = """
@@ -218,7 +218,7 @@ class Right(Widget, inherit_bindings=False):
218218
"""
219219

220220

221-
class Middle(Widget, inherit_bindings=False):
221+
class Middle(Widget):
222222
"""A container which aligns children on the Y axis."""
223223

224224
DEFAULT_CSS = """
@@ -230,7 +230,7 @@ class Middle(Widget, inherit_bindings=False):
230230
"""
231231

232232

233-
class CenterMiddle(Widget, inherit_bindings=False):
233+
class CenterMiddle(Widget):
234234
"""A container which aligns its children on both axis."""
235235

236236
DEFAULT_CSS = """
@@ -242,7 +242,7 @@ class CenterMiddle(Widget, inherit_bindings=False):
242242
"""
243243

244244

245-
class Grid(Widget, inherit_bindings=False):
245+
class Grid(Widget):
246246
"""A container with grid layout."""
247247

248248
DEFAULT_CSS = """
@@ -254,7 +254,7 @@ class Grid(Widget, inherit_bindings=False):
254254
"""
255255

256256

257-
class ItemGrid(Widget, inherit_bindings=False):
257+
class ItemGrid(Widget):
258258
"""A container with grid layout and automatic columns."""
259259

260260
DEFAULT_CSS = """

0 commit comments

Comments
 (0)