Skip to content

TabbedContent

Added in version 0.16.0

Switch between mutually exclusive content panes via a row of tabs.

  • Focusable
  • Container

This widget combines the Tabs and ContentSwitcher 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 constructor:

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 widget, which takes the tab title as the first parameter:

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 TabPanes.

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:

# 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:

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.

TabbedApp LetoJessicaPaul ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ Lady Jessica ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Bene Gesserit and concubine of Leto, and mother of Paul and Alia. PaulAlia ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ First child  L  Leto  J  Jessica  P  Paul 

from textual.app import App, ComposeResult
from textual.widgets import Footer, Label, Markdown, TabbedContent, TabPane

LETO = """
# Duke Leto I Atreides

Head of House Atreides.
"""

JESSICA = """
# Lady Jessica

Bene Gesserit and concubine of Leto, and mother of Paul and Alia.
"""

PAUL = """
# Paul Atreides

Son of Leto and Jessica.
"""


class TabbedApp(App):
    """An example of tabbed content."""

    BINDINGS = [
        ("l", "show_tab('leto')", "Leto"),
        ("j", "show_tab('jessica')", "Jessica"),
        ("p", "show_tab('paul')", "Paul"),
    ]

    def compose(self) -> ComposeResult:
        """Compose app with tabbed content."""
        # Footer to show keys
        yield Footer()

        # Add the TabbedContent widget
        with TabbedContent(initial="jessica"):
            with TabPane("Leto", id="leto"):  # First tab
                yield Markdown(LETO)  # Tab content
            with TabPane("Jessica", id="jessica"):
                yield Markdown(JESSICA)
                with TabbedContent("Paul", "Alia"):
                    yield TabPane("Paul", Label("First child"))
                    yield TabPane("Alia", Label("Second child"))

            with TabPane("Paul", id="paul"):
                yield Markdown(PAUL)

    def action_show_tab(self, tab: str) -> None:
        """Switch to a new tab."""
        self.get_child_by_type(TabbedContent).active = tab


if __name__ == "__main__":
    app = TabbedApp()
    app.run()

Styling

The TabbedContent widget is composed of two main sub-widgets: a Tabs and a ContentSwitcher; you can style them accordingly.

The tabs within the Tabs widget will have prefixed IDs; each ID being the ID of the TabPane the Tab is for, prefixed with --content-tab-. If you wish to style individual tabs within the TabbedContent widget you will need to use that prefix for the Tab IDs.

For example, to create a TabbedContent that has red and green labels:

ColorTabsApp RedGreen ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Red!

from textual.app import App, ComposeResult
from textual.widgets import Label, TabbedContent, TabPane


class ColorTabsApp(App):
    CSS = """
    TabbedContent #--content-tab-green {
        color: green;
    }

    TabbedContent #--content-tab-red {
        color: red;
    }
    """

    def compose(self) -> ComposeResult:
        with TabbedContent():
            with TabPane("Red", id="red"):
                yield Label("Red!")
            with TabPane("Green", id="green"):
                yield Label("Green!")


if __name__ == "__main__":
    ColorTabsApp().run()

Reactive Attributes

Name Type Default Description
active str "" The id attribute of the active tab. Set this to switch tabs.

Messages

Bindings

This widget has no bindings.

Component Classes

This widget has no component classes.

See also


textual.widgets.TabbedContent class

def __init__(
    self,
    *titles,
    initial="",
    name=None,
    id=None,
    classes=None,
    disabled=False
):

Bases: Widget

A container with associated tabs to toggle content visibility.

Parameters
Parameter Default Description
*titles
TextType
()

Positional argument will be used as title.

initial
str
''

The id of the initial tab, or empty string to select the first tab.

name
str | None
None

The name of the button.

id
str | None
None

The ID of the button in the DOM.

classes
str | None
None

The CSS classes of the button.

disabled
bool
False

Whether the button is disabled or not.

active class-attribute instance-attribute

active: reactive[str] = reactive('', init=False)

The ID of the active tab, or empty string if none are active.

active_pane property

active_pane: TabPane | None

The currently active pane, or None if no pane is active.

tab_count property

tab_count: int

Total number of tabs.

Cleared class

def __init__(self, tabbed_content):

Bases: Message

Posted when no tab pane is active.

This can happen if all tab panes are removed or if the currently active tab pane is unset.

Parameters
Parameter Default Description
tabbed_content
TabbedContent
required

The TabbedContent widget.

control property

control: TabbedContent

The TabbedContent widget that was cleared of all tab panes.

This is an alias for Cleared.tabbed_content and is used by the on decorator.

tabbed_content instance-attribute

tabbed_content = tabbed_content

The TabbedContent widget that contains the tab activated.

TabActivated class

def __init__(self, tabbed_content, tab):

Bases: Message

Posted when the active tab changes.

Parameters
Parameter Default Description
tabbed_content
TabbedContent
required

The TabbedContent widget.

tab
ContentTab
required

The Tab widget that was selected (contains the tab label).

ALLOW_SELECTOR_MATCH class-attribute instance-attribute

ALLOW_SELECTOR_MATCH = {'pane'}

Additional message attributes that can be used with the on decorator.

control property

control: TabbedContent

The TabbedContent widget that contains the tab activated.

This is an alias for TabActivated.tabbed_content and is used by the on decorator.

pane instance-attribute

pane = tabbed_content.get_pane(tab)

The TabPane widget that was activated by selecting the tab.

tab instance-attribute

tab = tab

The Tab widget that was selected (contains the tab label).

tabbed_content instance-attribute

tabbed_content = tabbed_content

The TabbedContent widget that contains the tab activated.

add_pane method

def add_pane(self, pane, *, before=None, after=None):

Add a new pane to the tabbed content.

Parameters
Parameter Default Description
pane
TabPane
required

The pane to add.

before
TabPane | str | None
None

Optional pane or pane ID to add the pane before.

after
TabPane | str | None
None

Optional pane or pane ID to add the pane after.

Returns
Type Description
AwaitComplete

An optionally awaitable object that waits for the pane to be added.

Raises
Type Description
Tabs.TabError

If there is a problem with the addition request.

Note

Only one of before or after can be provided. If both are provided an exception is raised.

clear_panes method

def clear_panes(self):

Remove all the panes in the tabbed content.

Returns
Type Description
AwaitComplete

An optionally awaitable object which waits for all panes to be removed and the Cleared message to be posted.

disable_tab method

def disable_tab(self, tab_id):

Disables the tab with the given ID.

Parameters
Parameter Default Description
tab_id
str
required

The ID of the TabPane to disable.

Raises
Type Description
Tabs.TabError

If there are any issues with the request.

enable_tab method

def enable_tab(self, tab_id):

Enables the tab with the given ID.

Parameters
Parameter Default Description
tab_id
str
required

The ID of the TabPane to enable.

Raises
Type Description
Tabs.TabError

If there are any issues with the request.

get_pane method

def get_pane(self, pane_id):

Get the TabPane associated with the given ID or tab.

Parameters
Parameter Default Description
pane_id
str | ContentTab
required

The ID of the pane to get, or the Tab it is associated with.

Returns
Type Description
TabPane

The TabPane associated with the ID or the given tab.

Raises
Type Description
ValueError

Raised if no ID was available.

get_tab method

def get_tab(self, pane_id):

Get the Tab associated with the given ID or TabPane.

Parameters
Parameter Default Description
pane_id
str | TabPane
required

The ID of the pane, or the pane itself.

Returns
Type Description
Tab

The Tab associated with the ID.

Raises
Type Description
ValueError

Raised if no ID was available.

hide_tab method

def hide_tab(self, tab_id):

Hides the tab with the given ID.

Parameters
Parameter Default Description
tab_id
str
required

The ID of the TabPane to hide.

Raises
Type Description
Tabs.TabError

If there are any issues with the request.

remove_pane method

def remove_pane(self, pane_id):

Remove a given pane from the tabbed content.

Parameters
Parameter Default Description
pane_id
str
required

The ID of the pane to remove.

Returns
Type Description
AwaitComplete

An optionally awaitable object that waits for the pane to be removed and the Cleared message to be posted.

show_tab method

def show_tab(self, tab_id):

Shows the tab with the given ID.

Parameters
Parameter Default Description
tab_id
str
required

The ID of the TabPane to show.

Raises
Type Description
Tabs.TabError

If there are any issues with the request.


textual.widgets.TabPane class

def __init__(
    self,
    title,
    *children,
    name=None,
    id=None,
    classes=None,
    disabled=False
):

Bases: Widget

A container for switchable content, with additional title.

This widget is intended to be used with TabbedContent.

Parameters
Parameter Default Description
title
TextType
required

Title of the TabPane (will be displayed in a tab label).

*children
Widget
()

Widget to go inside the TabPane.

name
str | None
None

Optional name for the TabPane.

id
str | None
None

Optional ID for the TabPane.

classes
str | None
None

Optional initial classes for the widget.

disabled
bool
False

Whether the TabPane is disabled or not.

Disabled class

Bases: TabPaneMessage

Sent when a tab pane is disabled via its reactive disabled.

Enabled class

Bases: TabPaneMessage

Sent when a tab pane is enabled via its reactive disabled.

TabPaneMessage class

Bases: Message

Base class for TabPane messages.

control property

control: TabPane

The tab pane that is the object of this message.

This is an alias for the attribute tab_pane and is used by the on decorator.

tab_pane instance-attribute

tab_pane: TabPane

The TabPane that is he object of this message.