diff --git a/reflex/app.py b/reflex/app.py index c4dff52fe..7992de291 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -457,6 +457,10 @@ class App(Base): # Generate the component if it is a callable. component = self._generate_component(component) + # unpack components that return tuples in an rx.fragment. + if isinstance(component, tuple): + component = Fragment.create(*component) + # Ensure state is enabled if this page uses state. if self.state is None: if on_load or component._has_event_triggers(): diff --git a/tests/test_app.py b/tests/test_app.py index 42f7c47be..9ac5c3f7a 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1355,3 +1355,32 @@ def test_app_state_determination(): # Referencing an event handler enables state. a4.add_page(rx.box(rx.button("Click", on_click=rx.console_log(""))), route="/") assert a4.state is not None + + +def test_add_page_component_returning_tuple(): + """Test that a component or render method returning a + tuple is unpacked in a Fragment. + """ + app = App() + + def index(): + return rx.text("first"), rx.text("second") + + def page2(): + return (rx.text("third"),) + + app.add_page(index) # type: ignore + app.add_page(page2) # type: ignore + + assert isinstance((fragment_wrapper := app.pages["index"].children[0]), Fragment) + assert isinstance((first_text := fragment_wrapper.children[0]), Text) + assert str(first_text.children[0].contents) == "{`first`}" # type: ignore + assert isinstance((second_text := fragment_wrapper.children[1]), Text) + assert str(second_text.children[0].contents) == "{`second`}" # type: ignore + + # Test page with trailing comma. + assert isinstance( + (page2_fragment_wrapper := app.pages["page2"].children[0]), Fragment + ) + assert isinstance((third_text := page2_fragment_wrapper.children[0]), Text) + assert str(third_text.children[0].contents) == "{`third`}" # type: ignore