Skip to content

Portal

wybthon.portal

portal

Portal component for rendering children into a different DOM container.

Use Portal to render content outside of the current component's DOM ancestor while keeping it part of the same reactive ownership tree (so signals, effects, and context still work). Common use cases include modals, tooltips, and toast notifications.

Functions:

Name Description
Portal

Render children into a different DOM container.

Portal

Portal(children: Union[VNode, List[VNode], None] = None, mount: Any = 'body') -> VNode

Render children into a different DOM container.

Matches SolidJS's <Portal mount={...}>. The children mount into mount (by default document.body) while remaining linked to the surrounding component's reactive scope, so signals, context, and lifecycle hooks still apply.

Parameters:

Name Type Description Default
children Union[VNode, List[VNode], None]

A single VNode or a list of them.

None
mount Any

The target container: an Element instance, a CSS selector string, or a kernel node id. Defaults to "body".

'body'

Returns:

Type Description
VNode

A component VNode whose children render inside mount.

Example
Show(
    when=show_modal,
    children=lambda: Portal(
        div(p("Modal content"), class_="modal"),
        mount="#modal-root",
    ),
)

What's in this module

Portal renders its children into a different DOM container while keeping them logically inside the component tree (so context, ownership, and event delegation still work). It matches SolidJS's <Portal> component.

This is the right tool for modals, tooltips, popovers, and toast notifications that need to escape the visual layout of their parent.

Usage

from wybthon import Portal, Show, component, create_signal
from wybthon.html import button, div, p


@component
def Modal():
    open_, set_open = create_signal(False)

    def toggle(_e):
        set_open(not open_())

    return div(
        button("Open", on_click=toggle),
        Show(
            when=open_,
            children=lambda: Portal(
                div(
                    p("I'm in document.body!"),
                    button("Close", on_click=toggle),
                    class_="modal",
                ),
                mount="body",
            ),
        ),
    )
  • mount accepts an Element, a CSS selector string, or a kernel node id. It defaults to "body".
  • The portal cleans up its content when its owner unmounts.
  • Events bubble through the component tree, not the DOM tree, which is handy for keeping modal logic close to the trigger.

See also