sycamore_web/
portal.rs

1use sycamore_macro::component;
2
3use crate::*;
4
5/// A portal into a different part of the DOM. Only renders in client side rendering (CSR) mode.
6/// Does nothing in SSR mode.
7#[component(inline_props)]
8pub fn Portal<'a, T: Into<View> + Default>(selector: &'a str, children: T) -> View {
9    if is_not_ssr!() {
10        let Some(parent) = document().query_selector(selector).unwrap() else {
11            panic!("element matching selector `{selector}` not found");
12        };
13
14        let start = HtmlNode::create_marker_node();
15        let start_node = start.as_web_sys().clone();
16        let end = HtmlNode::create_marker_node();
17        let end_node = end.as_web_sys().clone();
18        let children: View = (start, children.into(), end).into();
19
20        let nodes = children.as_web_sys();
21        for node in &nodes {
22            parent.append_child(node).unwrap();
23        }
24
25        on_cleanup(move || {
26            let nodes = utils::get_nodes_between(&start_node, &end_node);
27            for node in nodes {
28                parent.remove_child(&node).unwrap();
29            }
30            parent.remove_child(&start_node).unwrap();
31            parent.remove_child(&end_node).unwrap();
32        });
33    }
34    View::default()
35}