Files
textual/docs/widgets/tabbed_content.md
Will McGugan f5e779c4c4 tabbed content widget (#2059)
* tabbed content widget

* TabbedContent widget and docs

* missing docs

* fix active

* doc fix

* test fix

* additional test

* test for render_str

* docstring

* changelog

* doc update

* changelog

* fix bad optimization

* Update docs/widgets/tabbed_content.md

Co-authored-by: Dave Pearson <davep@davep.org>

* fix for empty initial

* docstrings

* Update src/textual/widgets/_content_switcher.py

Co-authored-by: Dave Pearson <davep@davep.org>

* docstring

* remove log

* permit nested tabs

* renamed TabsCleared to Cleared

* added tests, fix types on click

* tests

* fix broken test

* fix for nested tabs

---------

Co-authored-by: Dave Pearson <davep@davep.org>
2023-03-18 10:38:41 +00:00

107 lines
3.1 KiB
Markdown

# TabbedContent
Switch between mutually exclusive content panes via a row of tabs.
- [x] Focusable
- [x] Container
This widget combines the [Tabs](../widgets/tabs.md) and [ContentSwitcher](../widgets/content_switcher.md) widgets to create a convenient way of navigating content.
Only a single child of TabbedContent is visible at once.
Each child has an associated tab which will make it visible and hide the others.
## Composing
There are two ways to provide the titles for the tab.
You can pass them as positional arguments to the [TabbedContent][textual.widgets.TabbedContent] constructor:
```python
def compose(self) -> ComposeResult:
with TabbedContent("Leto", "Jessica", "Paul"):
yield Markdown(LETO)
yield Markdown(JESSICA)
yield Markdown(PAUL)
```
Alternatively you can wrap the content in a [TabPane][textual.widgets.TabPane] widget, which takes the tab title as the first parameter:
```python
def compose(self) -> ComposeResult:
with TabbedContent():
with TabPane("Leto"):
yield Markdown(LETO)
with TabPane("Jessica"):
yield Markdown(JESSICA)
with TabPane("Paul"):
yield Markdown(PAUL)
```
## Switching tabs
If you need to programmatically switch tabs, you should provide an `id` attribute to the `TabPane`s.
```python
def compose(self) -> ComposeResult:
with TabbedContent():
with TabPane("Leto", id="leto"):
yield Markdown(LETO)
with TabPane("Jessica", id="jessica"):
yield Markdown(JESSICA)
with TabPane("Paul", id="paul"):
yield Markdown(PAUL)
```
You can then switch tabs by setting the `active` reactive attribute:
```python
# Switch to Jessica tab
self.query_one(TabbedContent).active = "jessica"
```
!!! note
If you don't provide `id` attributes to the tab panes, they will be assigned sequentially starting at `tab-1` (then `tab-2` etc).
## Initial tab
The first child of `TabbedContent` will be the initial active tab by default. You can pick a different initial tab by setting the `initial` argument to the `id` of the tab:
```python
def compose(self) -> ComposeResult:
with TabbedContent(initial="jessica"):
with TabPane("Leto", id="leto"):
yield Markdown(LETO)
with TabPane("Jessica", id="jessica"):
yield Markdown(JESSICA)
with TabPane("Paul", id="paul"):
yield Markdown(PAUL)
```
## Example
The following example contains a `TabbedContent` with three tabs.
=== "Output"
```{.textual path="docs/examples/widgets/tabbed_content.py"}
```
=== "tabbed_content.py"
```python
--8<-- "docs/examples/widgets/tabbed_content.py"
```
## Reactive attributes
| Name | Type | Default | Description |
| -------- | ----- | ------- | -------------------------------------------------------------- |
| `active` | `str` | `""` | The `id` attribute of the active tab. Set this to switch tabs. |
## See also
- [TabbedContent](../api/tabbed_content.md) code reference.
- [Tabs](../api/tabs.md) code reference.
- [ContentSwitcher](../api/content_switcher.md) code reference.