We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
It's possible to somehow break the working of `TabbedContent`
This one isn't exactly easy to explain, but hopefully easy to see and recreate with the following code (which is a distilled version of what I'm doing in a bigger application, where I found it).

Worth noting: the motivation here is that (in the application I'm working on) the `TabbedContent` is acting as a sidebar, where each pane has content that can be focused, and I want folk to be people to switch tabs without needing to navigate to the tab bar and back into the pane again. As such there's some bindings in place that call into the `Tabs` and uses their prev/next tab actions.

```python
from textual.app        import App, ComposeResult
from textual.binding    import Binding
from textual.containers import Vertical
from textual.widgets    import Header, Footer, TabbedContent, TabPane, Tabs, DirectoryTree

class SelfFocusPane(TabPane):

    DEFAULT_CSS = """
    SelfFocusPane {
        height: 100% !important;
    }
    DirectoryTree {
        width: 100%;
        height: 100% !important;
    }
    """

    def compose( self ) -> ComposeResult:
        """Compose the child widgets."""
        yield DirectoryTree(".")

    def on_show( self ) -> None:
        self.query_one( DirectoryTree ).focus()

class TabbedContentIssueApp( App[ None ] ):

    CSS = """
    Screen {
        align: center middle;
    }

    Screen > Vertical {
        width: 42;
    }

    TabbedContent {
        border: round red;
        max-width: 40;
        height: 100%;
    }

    ContentSwitcher {
        height: 1fr !important;
    }
    """

    BINDINGS = [
        Binding( "shift+left", "previous", "Previous" ),
        Binding( "shift+right", "next", "Next" ),
    ]

    def compose( self ) -> ComposeResult:
        yield Header()
        with Vertical():
            with TabbedContent():
                for n in range( 6 ):
                    yield SelfFocusPane( f"Tab {n}")
        yield Footer()

    def on_mount(self) -> None:
        self.query_one(Tabs).focus()

    def action_previous(self) -> None:
        self.query_one(Tabs).action_previous_tab()

    def action_next(self) -> None:
        self.query_one(Tabs).action_next_tab()

if __name__ == "__main__":
    TabbedContentIssueApp().run()
```

In experimenting, it looks like the `SelfFocusPane.on_show` setting focus to the child of the pane is key here; remove that and I can't recreate the issue.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/textual/widgets/_tabbed_content.py`
Content:
```
1 from __future__ import annotations
2 
3 from itertools import zip_longest
4 
5 from rich.repr import Result
6 from rich.text import Text, TextType
7 
8 from ..app import ComposeResult
9 from ..message import Message
10 from ..reactive import reactive
11 from ..widget import Widget
12 from ._content_switcher import ContentSwitcher
13 from ._tabs import Tab, Tabs
14 
15 __all__ = [
16     "ContentTab",
17     "TabbedContent",
18     "TabPane",
19 ]
20 
21 
22 class ContentTab(Tab):
23     """A Tab with an associated content id."""
24 
25     def __init__(self, label: Text, content_id: str):
26         """Initialize a ContentTab.
27 
28         Args:
29             label: The label to be displayed within the tab.
30             content_id: The id of the content associated with the tab.
31         """
32         super().__init__(label, id=content_id)
33 
34 
35 class TabPane(Widget):
36     """A container for switchable content, with additional title.
37 
38     This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent].
39 
40     """
41 
42     DEFAULT_CSS = """
43     TabPane {
44         height: auto;
45         padding: 1 2;
46     }
47     """
48 
49     def __init__(
50         self,
51         title: TextType,
52         *children: Widget,
53         name: str | None = None,
54         id: str | None = None,
55         classes: str | None = None,
56         disabled: bool = False,
57     ):
58         """Initialize a TabPane.
59 
60         Args:
61             title: Title of the TabPane (will be displayed in a tab label).
62             *children: Widget to go inside the TabPane.
63             name: Optional name for the TabPane.
64             id: Optional ID for the TabPane.
65             classes: Optional initial classes for the widget.
66             disabled: Whether the TabPane is disabled or not.
67         """
68         self._title = self.render_str(title)
69         super().__init__(
70             *children, name=name, id=id, classes=classes, disabled=disabled
71         )
72 
73 
74 class TabbedContent(Widget):
75     """A container with associated tabs to toggle content visibility."""
76 
77     DEFAULT_CSS = """
78     TabbedContent {
79         height: auto;
80     }
81     TabbedContent > ContentSwitcher {
82         height: auto;
83     }
84     """
85 
86     active: reactive[str] = reactive("", init=False)
87     """The ID of the active tab, or empty string if none are active."""
88 
89     class TabActivated(Message):
90         """Posted when the active tab changes."""
91 
92         def __init__(self, tabbed_content: TabbedContent, tab: Tab) -> None:
93             """Initialize message.
94 
95             Args:
96                 tabbed_content: The TabbedContent widget.
97                 tab: The Tab widget that was selected (contains the tab label).
98             """
99             self.tabbed_content = tabbed_content
100             self.tab = tab
101             super().__init__()
102 
103         def __rich_repr__(self) -> Result:
104             yield self.tabbed_content
105             yield self.tab
106 
107     def __init__(self, *titles: TextType, initial: str = "") -> None:
108         """Initialize a TabbedContent widgets.
109 
110         Args:
111             *titles: Positional argument will be used as title.
112             initial: The id of the initial tab, or empty string to select the first tab.
113         """
114         self.titles = [self.render_str(title) for title in titles]
115         self._tab_content: list[Widget] = []
116         self._initial = initial
117         super().__init__()
118 
119     def validate_active(self, active: str) -> str:
120         """It doesn't make sense for `active` to be an empty string.
121 
122         Args:
123             active: Attribute to be validated.
124 
125         Returns:
126             Value of `active`.
127 
128         Raises:
129             ValueError: If the active attribute is set to empty string.
130         """
131         if not active:
132             raise ValueError("'active' tab must not be empty string.")
133         return active
134 
135     def compose(self) -> ComposeResult:
136         """Compose the tabbed content."""
137 
138         def set_id(content: TabPane, new_id: str) -> TabPane:
139             """Set an id on the content, if not already present.
140 
141             Args:
142                 content: a TabPane.
143                 new_id: New `is` attribute, if it is not already set.
144 
145             Returns:
146                 The same TabPane.
147             """
148             if content.id is None:
149                 content.id = new_id
150             return content
151 
152         # Wrap content in a `TabPane` if required.
153         pane_content = [
154             (
155                 set_id(content, f"tab-{index}")
156                 if isinstance(content, TabPane)
157                 else TabPane(
158                     title or self.render_str(f"Tab {index}"), content, id=f"tab-{index}"
159                 )
160             )
161             for index, (title, content) in enumerate(
162                 zip_longest(self.titles, self._tab_content), 1
163             )
164         ]
165         # Get a tab for each pane
166         tabs = [
167             ContentTab(content._title, content.id or "") for content in pane_content
168         ]
169         # Yield the tabs
170         yield Tabs(*tabs, active=self._initial or None)
171         # Yield the content switcher and panes
172         with ContentSwitcher(initial=self._initial or None):
173             yield from pane_content
174 
175     def compose_add_child(self, widget: Widget) -> None:
176         """When using the context manager compose syntax, we want to attach nodes to the switcher.
177 
178         Args:
179             widget: A Widget to add.
180         """
181         self._tab_content.append(widget)
182 
183     def _on_tabs_tab_activated(self, event: Tabs.TabActivated) -> None:
184         """User clicked a tab."""
185         event.stop()
186         switcher = self.get_child_by_type(ContentSwitcher)
187         assert isinstance(event.tab, ContentTab)
188         switcher.current = event.tab.id
189         self.active = event.tab.id
190         self.post_message(
191             TabbedContent.TabActivated(
192                 tabbed_content=self,
193                 tab=event.tab,
194             )
195         )
196 
197     def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:
198         """All tabs were removed."""
199         event.stop()
200 
201     def watch_active(self, active: str) -> None:
202         """Switch tabs when the active attributes changes."""
203         self.get_child_by_type(Tabs).active = active
204
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/textual/widgets/_tabbed_content.py b/src/textual/widgets/_tabbed_content.py
--- a/src/textual/widgets/_tabbed_content.py
+++ b/src/textual/widgets/_tabbed_content.py
@@ -83,9 +83,6 @@
     }
     """
 
-    active: reactive[str] = reactive("", init=False)
-    """The ID of the active tab, or empty string if none are active."""
-
     class TabActivated(Message):
         """Posted when the active tab changes."""
 
@@ -116,21 +113,16 @@
         self._initial = initial
         super().__init__()
 
-    def validate_active(self, active: str) -> str:
-        """It doesn't make sense for `active` to be an empty string.
-
-        Args:
-            active: Attribute to be validated.
-
-        Returns:
-            Value of `active`.
+    @property
+    def active(self) -> str:
+        """The ID of the active tab, or empty string if none are active."""
+        return self.get_child_by_type(Tabs).active
 
-        Raises:
-            ValueError: If the active attribute is set to empty string.
-        """
+    @active.setter
+    def active(self, active: str) -> None:
         if not active:
             raise ValueError("'active' tab must not be empty string.")
-        return active
+        self.get_child_by_type(Tabs).active = active
 
     def compose(self) -> ComposeResult:
         """Compose the tabbed content."""
@@ -186,7 +178,6 @@
         switcher = self.get_child_by_type(ContentSwitcher)
         assert isinstance(event.tab, ContentTab)
         switcher.current = event.tab.id
-        self.active = event.tab.id
         self.post_message(
             TabbedContent.TabActivated(
                 tabbed_content=self,
@@ -197,7 +188,3 @@
     def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:
         """All tabs were removed."""
         event.stop()
-
-    def watch_active(self, active: str) -> None:
-        """Switch tabs when the active attributes changes."""
-        self.get_child_by_type(Tabs).active = active

{"golden_diff": "diff --git a/src/textual/widgets/_tabbed_content.py b/src/textual/widgets/_tabbed_content.py\n--- a/src/textual/widgets/_tabbed_content.py\n+++ b/src/textual/widgets/_tabbed_content.py\n@@ -83,9 +83,6 @@\n     }\n     \"\"\"\n \n-    active: reactive[str] = reactive(\"\", init=False)\n-    \"\"\"The ID of the active tab, or empty string if none are active.\"\"\"\n-\n     class TabActivated(Message):\n         \"\"\"Posted when the active tab changes.\"\"\"\n \n@@ -116,21 +113,16 @@\n         self._initial = initial\n         super().__init__()\n \n-    def validate_active(self, active: str) -> str:\n-        \"\"\"It doesn't make sense for `active` to be an empty string.\n-\n-        Args:\n-            active: Attribute to be validated.\n-\n-        Returns:\n-            Value of `active`.\n+    @property\n+    def active(self) -> str:\n+        \"\"\"The ID of the active tab, or empty string if none are active.\"\"\"\n+        return self.get_child_by_type(Tabs).active\n \n-        Raises:\n-            ValueError: If the active attribute is set to empty string.\n-        \"\"\"\n+    @active.setter\n+    def active(self, active: str) -> None:\n         if not active:\n             raise ValueError(\"'active' tab must not be empty string.\")\n-        return active\n+        self.get_child_by_type(Tabs).active = active\n \n     def compose(self) -> ComposeResult:\n         \"\"\"Compose the tabbed content.\"\"\"\n@@ -186,7 +178,6 @@\n         switcher = self.get_child_by_type(ContentSwitcher)\n         assert isinstance(event.tab, ContentTab)\n         switcher.current = event.tab.id\n-        self.active = event.tab.id\n         self.post_message(\n             TabbedContent.TabActivated(\n                 tabbed_content=self,\n@@ -197,7 +188,3 @@\n     def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:\n         \"\"\"All tabs were removed.\"\"\"\n         event.stop()\n-\n-    def watch_active(self, active: str) -> None:\n-        \"\"\"Switch tabs when the active attributes changes.\"\"\"\n-        self.get_child_by_type(Tabs).active = active\n", "issue": "It's possible to somehow break the working of `TabbedContent`\nThis one isn't exactly easy to explain, but hopefully easy to see and recreate with the following code (which is a distilled version of what I'm doing in a bigger application, where I found it).\r\n\r\nWorth noting: the motivation here is that (in the application I'm working on) the `TabbedContent` is acting as a sidebar, where each pane has content that can be focused, and I want folk to be people to switch tabs without needing to navigate to the tab bar and back into the pane again. As such there's some bindings in place that call into the `Tabs` and uses their prev/next tab actions.\r\n\r\n```python\r\nfrom textual.app        import App, ComposeResult\r\nfrom textual.binding    import Binding\r\nfrom textual.containers import Vertical\r\nfrom textual.widgets    import Header, Footer, TabbedContent, TabPane, Tabs, DirectoryTree\r\n\r\nclass SelfFocusPane(TabPane):\r\n\r\n    DEFAULT_CSS = \"\"\"\r\n    SelfFocusPane {\r\n        height: 100% !important;\r\n    }\r\n    DirectoryTree {\r\n        width: 100%;\r\n        height: 100% !important;\r\n    }\r\n    \"\"\"\r\n\r\n    def compose( self ) -> ComposeResult:\r\n        \"\"\"Compose the child widgets.\"\"\"\r\n        yield DirectoryTree(\".\")\r\n\r\n    def on_show( self ) -> None:\r\n        self.query_one( DirectoryTree ).focus()\r\n\r\nclass TabbedContentIssueApp( App[ None ] ):\r\n\r\n    CSS = \"\"\"\r\n    Screen {\r\n        align: center middle;\r\n    }\r\n\r\n    Screen > Vertical {\r\n        width: 42;\r\n    }\r\n\r\n    TabbedContent {\r\n        border: round red;\r\n        max-width: 40;\r\n        height: 100%;\r\n    }\r\n\r\n    ContentSwitcher {\r\n        height: 1fr !important;\r\n    }\r\n    \"\"\"\r\n\r\n    BINDINGS = [\r\n        Binding( \"shift+left\", \"previous\", \"Previous\" ),\r\n        Binding( \"shift+right\", \"next\", \"Next\" ),\r\n    ]\r\n\r\n    def compose( self ) -> ComposeResult:\r\n        yield Header()\r\n        with Vertical():\r\n            with TabbedContent():\r\n                for n in range( 6 ):\r\n                    yield SelfFocusPane( f\"Tab {n}\")\r\n        yield Footer()\r\n\r\n    def on_mount(self) -> None:\r\n        self.query_one(Tabs).focus()\r\n\r\n    def action_previous(self) -> None:\r\n        self.query_one(Tabs).action_previous_tab()\r\n\r\n    def action_next(self) -> None:\r\n        self.query_one(Tabs).action_next_tab()\r\n\r\nif __name__ == \"__main__\":\r\n    TabbedContentIssueApp().run()\r\n```\r\n\r\nIn experimenting, it looks like the `SelfFocusPane.on_show` setting focus to the child of the pane is key here; remove that and I can't recreate the issue.\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom itertools import zip_longest\n\nfrom rich.repr import Result\nfrom rich.text import Text, TextType\n\nfrom ..app import ComposeResult\nfrom ..message import Message\nfrom ..reactive import reactive\nfrom ..widget import Widget\nfrom ._content_switcher import ContentSwitcher\nfrom ._tabs import Tab, Tabs\n\n__all__ = [\n    \"ContentTab\",\n    \"TabbedContent\",\n    \"TabPane\",\n]\n\n\nclass ContentTab(Tab):\n    \"\"\"A Tab with an associated content id.\"\"\"\n\n    def __init__(self, label: Text, content_id: str):\n        \"\"\"Initialize a ContentTab.\n\n        Args:\n            label: The label to be displayed within the tab.\n            content_id: The id of the content associated with the tab.\n        \"\"\"\n        super().__init__(label, id=content_id)\n\n\nclass TabPane(Widget):\n    \"\"\"A container for switchable content, with additional title.\n\n    This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent].\n\n    \"\"\"\n\n    DEFAULT_CSS = \"\"\"\n    TabPane {\n        height: auto;\n        padding: 1 2;\n    }\n    \"\"\"\n\n    def __init__(\n        self,\n        title: TextType,\n        *children: Widget,\n        name: str | None = None,\n        id: str | None = None,\n        classes: str | None = None,\n        disabled: bool = False,\n    ):\n        \"\"\"Initialize a TabPane.\n\n        Args:\n            title: Title of the TabPane (will be displayed in a tab label).\n            *children: Widget to go inside the TabPane.\n            name: Optional name for the TabPane.\n            id: Optional ID for the TabPane.\n            classes: Optional initial classes for the widget.\n            disabled: Whether the TabPane is disabled or not.\n        \"\"\"\n        self._title = self.render_str(title)\n        super().__init__(\n            *children, name=name, id=id, classes=classes, disabled=disabled\n        )\n\n\nclass TabbedContent(Widget):\n    \"\"\"A container with associated tabs to toggle content visibility.\"\"\"\n\n    DEFAULT_CSS = \"\"\"\n    TabbedContent {\n        height: auto;\n    }\n    TabbedContent > ContentSwitcher {\n        height: auto;\n    }\n    \"\"\"\n\n    active: reactive[str] = reactive(\"\", init=False)\n    \"\"\"The ID of the active tab, or empty string if none are active.\"\"\"\n\n    class TabActivated(Message):\n        \"\"\"Posted when the active tab changes.\"\"\"\n\n        def __init__(self, tabbed_content: TabbedContent, tab: Tab) -> None:\n            \"\"\"Initialize message.\n\n            Args:\n                tabbed_content: The TabbedContent widget.\n                tab: The Tab widget that was selected (contains the tab label).\n            \"\"\"\n            self.tabbed_content = tabbed_content\n            self.tab = tab\n            super().__init__()\n\n        def __rich_repr__(self) -> Result:\n            yield self.tabbed_content\n            yield self.tab\n\n    def __init__(self, *titles: TextType, initial: str = \"\") -> None:\n        \"\"\"Initialize a TabbedContent widgets.\n\n        Args:\n            *titles: Positional argument will be used as title.\n            initial: The id of the initial tab, or empty string to select the first tab.\n        \"\"\"\n        self.titles = [self.render_str(title) for title in titles]\n        self._tab_content: list[Widget] = []\n        self._initial = initial\n        super().__init__()\n\n    def validate_active(self, active: str) -> str:\n        \"\"\"It doesn't make sense for `active` to be an empty string.\n\n        Args:\n            active: Attribute to be validated.\n\n        Returns:\n            Value of `active`.\n\n        Raises:\n            ValueError: If the active attribute is set to empty string.\n        \"\"\"\n        if not active:\n            raise ValueError(\"'active' tab must not be empty string.\")\n        return active\n\n    def compose(self) -> ComposeResult:\n        \"\"\"Compose the tabbed content.\"\"\"\n\n        def set_id(content: TabPane, new_id: str) -> TabPane:\n            \"\"\"Set an id on the content, if not already present.\n\n            Args:\n                content: a TabPane.\n                new_id: New `is` attribute, if it is not already set.\n\n            Returns:\n                The same TabPane.\n            \"\"\"\n            if content.id is None:\n                content.id = new_id\n            return content\n\n        # Wrap content in a `TabPane` if required.\n        pane_content = [\n            (\n                set_id(content, f\"tab-{index}\")\n                if isinstance(content, TabPane)\n                else TabPane(\n                    title or self.render_str(f\"Tab {index}\"), content, id=f\"tab-{index}\"\n                )\n            )\n            for index, (title, content) in enumerate(\n                zip_longest(self.titles, self._tab_content), 1\n            )\n        ]\n        # Get a tab for each pane\n        tabs = [\n            ContentTab(content._title, content.id or \"\") for content in pane_content\n        ]\n        # Yield the tabs\n        yield Tabs(*tabs, active=self._initial or None)\n        # Yield the content switcher and panes\n        with ContentSwitcher(initial=self._initial or None):\n            yield from pane_content\n\n    def compose_add_child(self, widget: Widget) -> None:\n        \"\"\"When using the context manager compose syntax, we want to attach nodes to the switcher.\n\n        Args:\n            widget: A Widget to add.\n        \"\"\"\n        self._tab_content.append(widget)\n\n    def _on_tabs_tab_activated(self, event: Tabs.TabActivated) -> None:\n        \"\"\"User clicked a tab.\"\"\"\n        event.stop()\n        switcher = self.get_child_by_type(ContentSwitcher)\n        assert isinstance(event.tab, ContentTab)\n        switcher.current = event.tab.id\n        self.active = event.tab.id\n        self.post_message(\n            TabbedContent.TabActivated(\n                tabbed_content=self,\n                tab=event.tab,\n            )\n        )\n\n    def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:\n        \"\"\"All tabs were removed.\"\"\"\n        event.stop()\n\n    def watch_active(self, active: str) -> None:\n        \"\"\"Switch tabs when the active attributes changes.\"\"\"\n        self.get_child_by_type(Tabs).active = active\n", "path": "src/textual/widgets/_tabbed_content.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom itertools import zip_longest\n\nfrom rich.repr import Result\nfrom rich.text import Text, TextType\n\nfrom ..app import ComposeResult\nfrom ..message import Message\nfrom ..reactive import reactive\nfrom ..widget import Widget\nfrom ._content_switcher import ContentSwitcher\nfrom ._tabs import Tab, Tabs\n\n__all__ = [\n    \"ContentTab\",\n    \"TabbedContent\",\n    \"TabPane\",\n]\n\n\nclass ContentTab(Tab):\n    \"\"\"A Tab with an associated content id.\"\"\"\n\n    def __init__(self, label: Text, content_id: str):\n        \"\"\"Initialize a ContentTab.\n\n        Args:\n            label: The label to be displayed within the tab.\n            content_id: The id of the content associated with the tab.\n        \"\"\"\n        super().__init__(label, id=content_id)\n\n\nclass TabPane(Widget):\n    \"\"\"A container for switchable content, with additional title.\n\n    This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent].\n\n    \"\"\"\n\n    DEFAULT_CSS = \"\"\"\n    TabPane {\n        height: auto;\n        padding: 1 2;\n    }\n    \"\"\"\n\n    def __init__(\n        self,\n        title: TextType,\n        *children: Widget,\n        name: str | None = None,\n        id: str | None = None,\n        classes: str | None = None,\n        disabled: bool = False,\n    ):\n        \"\"\"Initialize a TabPane.\n\n        Args:\n            title: Title of the TabPane (will be displayed in a tab label).\n            *children: Widget to go inside the TabPane.\n            name: Optional name for the TabPane.\n            id: Optional ID for the TabPane.\n            classes: Optional initial classes for the widget.\n            disabled: Whether the TabPane is disabled or not.\n        \"\"\"\n        self._title = self.render_str(title)\n        super().__init__(\n            *children, name=name, id=id, classes=classes, disabled=disabled\n        )\n\n\nclass TabbedContent(Widget):\n    \"\"\"A container with associated tabs to toggle content visibility.\"\"\"\n\n    DEFAULT_CSS = \"\"\"\n    TabbedContent {\n        height: auto;\n    }\n    TabbedContent > ContentSwitcher {\n        height: auto;\n    }\n    \"\"\"\n\n    class TabActivated(Message):\n        \"\"\"Posted when the active tab changes.\"\"\"\n\n        def __init__(self, tabbed_content: TabbedContent, tab: Tab) -> None:\n            \"\"\"Initialize message.\n\n            Args:\n                tabbed_content: The TabbedContent widget.\n                tab: The Tab widget that was selected (contains the tab label).\n            \"\"\"\n            self.tabbed_content = tabbed_content\n            self.tab = tab\n            super().__init__()\n\n        def __rich_repr__(self) -> Result:\n            yield self.tabbed_content\n            yield self.tab\n\n    def __init__(self, *titles: TextType, initial: str = \"\") -> None:\n        \"\"\"Initialize a TabbedContent widgets.\n\n        Args:\n            *titles: Positional argument will be used as title.\n            initial: The id of the initial tab, or empty string to select the first tab.\n        \"\"\"\n        self.titles = [self.render_str(title) for title in titles]\n        self._tab_content: list[Widget] = []\n        self._initial = initial\n        super().__init__()\n\n    @property\n    def active(self) -> str:\n        \"\"\"The ID of the active tab, or empty string if none are active.\"\"\"\n        return self.get_child_by_type(Tabs).active\n\n    @active.setter\n    def active(self, active: str) -> None:\n        if not active:\n            raise ValueError(\"'active' tab must not be empty string.\")\n        self.get_child_by_type(Tabs).active = active\n\n    def compose(self) -> ComposeResult:\n        \"\"\"Compose the tabbed content.\"\"\"\n\n        def set_id(content: TabPane, new_id: str) -> TabPane:\n            \"\"\"Set an id on the content, if not already present.\n\n            Args:\n                content: a TabPane.\n                new_id: New `is` attribute, if it is not already set.\n\n            Returns:\n                The same TabPane.\n            \"\"\"\n            if content.id is None:\n                content.id = new_id\n            return content\n\n        # Wrap content in a `TabPane` if required.\n        pane_content = [\n            (\n                set_id(content, f\"tab-{index}\")\n                if isinstance(content, TabPane)\n                else TabPane(\n                    title or self.render_str(f\"Tab {index}\"), content, id=f\"tab-{index}\"\n                )\n            )\n            for index, (title, content) in enumerate(\n                zip_longest(self.titles, self._tab_content), 1\n            )\n        ]\n        # Get a tab for each pane\n        tabs = [\n            ContentTab(content._title, content.id or \"\") for content in pane_content\n        ]\n        # Yield the tabs\n        yield Tabs(*tabs, active=self._initial or None)\n        # Yield the content switcher and panes\n        with ContentSwitcher(initial=self._initial or None):\n            yield from pane_content\n\n    def compose_add_child(self, widget: Widget) -> None:\n        \"\"\"When using the context manager compose syntax, we want to attach nodes to the switcher.\n\n        Args:\n            widget: A Widget to add.\n        \"\"\"\n        self._tab_content.append(widget)\n\n    def _on_tabs_tab_activated(self, event: Tabs.TabActivated) -> None:\n        \"\"\"User clicked a tab.\"\"\"\n        event.stop()\n        switcher = self.get_child_by_type(ContentSwitcher)\n        assert isinstance(event.tab, ContentTab)\n        switcher.current = event.tab.id\n        self.post_message(\n            TabbedContent.TabActivated(\n                tabbed_content=self,\n                tab=event.tab,\n            )\n        )\n\n    def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:\n        \"\"\"All tabs were removed.\"\"\"\n        event.stop()\n", "path": "src/textual/widgets/_tabbed_content.py"}]}