For an AI

Portals

Need a dialog or anchored menu? Use Modal / Popup — they ship native <dialog> / popover with focus restore. portal() only moves DOM nodes (toasts, custom shells).

LIVE

<Modal> (prefer over portal())

Stacked modal

ESC and backdrop dismiss. Focus returns to this trigger.

Prefer Modal / Popup

view! {
    <Modal id="confirm">
        <button slot="trigger" type="button">"Open"</button>
        <p>"Focus-trapped dialog"</p>
    </Modal>
}

Portal target

Add a target element in your layout shell:

view! {
    <>
        <main><Slot /></main>
        <div id="modal-root" data-r-portal-target="modal"></div>
    </>
}

Portal content

#[component]
fn Modal(open: bool, children: Vec<Child>) -> View {
    if !open {
        return view! { <></> };
    }
    portal("modal", children)
}

view! {
    <Modal open={show_modal.get()}>
        <div class="modal-backdrop">
            <div class="modal">"Dialog content"</div>
        </div>
    </Modal>
}

data-r-portal

SSR emits a <template data-r-portal="modal">. After resume, the runtime moves children into the matching data-r-portal-target element.