From b7a7c2c58e333e2e2434c1de3ac5c9e9978d9177 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 09:04:36 -0400 Subject: [PATCH] Initialize collapsible title from its complete content --- src/textual/widgets/_collapsible.py | 9 ++++++--- tests/test_collapsible.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/textual/widgets/_collapsible.py b/src/textual/widgets/_collapsible.py index 066c887f9be..409627811c5 100644 --- a/src/textual/widgets/_collapsible.py +++ b/src/textual/widgets/_collapsible.py @@ -51,7 +51,7 @@ class CollapsibleTitle(Static, can_focus=True): """ collapsed = reactive(True) - label: reactive[ContentText] = reactive(Content("Toggle")) + label: reactive[ContentText] = reactive(Content("Toggle"), always_update=True) def __init__( self, @@ -64,8 +64,11 @@ def __init__( super().__init__() self.collapsed_symbol = collapsed_symbol self.expanded_symbol = expanded_symbol - self.label = Content.from_text(label) - self.collapsed = collapsed + # Both inputs belong to the initial title. Do not render reactive + # defaults or an intermediate collapsed symbol before acquiring them. + self.set_reactive(CollapsibleTitle.label, Content.from_text(label)) + self.set_reactive(CollapsibleTitle.collapsed, collapsed) + self._update_label() class Toggle(Message): """Request toggle.""" diff --git a/tests/test_collapsible.py b/tests/test_collapsible.py index 5cbb973f3f0..05247bc3767 100644 --- a/tests/test_collapsible.py +++ b/tests/test_collapsible.py @@ -2,12 +2,38 @@ from textual import on from textual.app import App, ComposeResult +from textual.content import Content from textual.widgets import Collapsible, Label from textual.widgets._collapsible import CollapsibleTitle COLLAPSED_CLASS = "-collapsed" +async def test_title_initial_content_and_same_text_style(): + title = CollapsibleTitle( + label=Content.from_markup("[red]original[/red]"), + collapsed_symbol="+", + expanded_symbol="---", + collapsed=False, + ) + assert title.content.is_same(Content.assemble("---", " ", Content.from_markup("[red]original[/red]"))) + app = App() + async with app.run_test() as pilot: + await app.mount(title) + await pilot.pause() + revision = title._layout_updates + title.label = Content.from_markup("[blue]original[/blue]") + assert title.content.is_same( + Content.assemble("---", " ", Content.from_markup("[blue]original[/blue]")) + ) + assert title._layout_updates == revision + title.collapsed = True + assert title.content.plain == "+ original" + assert title._layout_updates > revision + await pilot.pause() + assert title.region.width == len("+ original") + 2 + + def get_title(collapsible: Collapsible) -> CollapsibleTitle: return collapsible.get_child_by_type(CollapsibleTitle)