DioxusLabs / dioxus

Fullstack GUI library for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
19.27k stars 733 forks source link

Placeholders in SVGs break rendering #2274

Open xvlunar opened 2 months ago

xvlunar commented 2 months ago

Problem

In the code below props.icon.child_elements() returns a Element from a rsx! macro. With just the 'web' feature this works fine, however with fullstack this causes the children_elements to render side by side the parent svg.

What is rendered in the html

<svg></svg>
<path></path>

What should be rendered in the html

<svg><path></path></svg>
#[allow(non_snake_case)]
pub fn Icon<T: IconShape + Clone + PartialEq + 'static>(props: IconProps<T>) -> Element {
    rsx!(
        svg {
            stroke_width: "0",
            class: "{props.class}",
            height: "{props.height}",
            width: "{props.width}",
            view_box: "{props.icon.view_box()}",
            xmlns: "{props.icon.xmlns()}",
            fill: "{props.fill}",
            stroke: "{props.fill}",
            if let Some(title_text) = props.title {
                title {
                    "{title_text}"
                }
            },
            {props.icon.child_elements()} // This is what returns a Element using rsx!{}
        }
    )
}

Steps To Reproduce use dioxus-free-icons and try to render one with fullstack. ( I think sometimes it works but rarely, so try a couple times)

Expected behavior Expect the path to be inside the svg

Environment:

Questionnaire

ealmloff commented 2 months ago

This is caused by a <pre> tag dioxus renders as a placeholder for the if let Some(title_text) = props.title { statement. If you look at the network tab, dioxus renderes something like:

<svg ... data-node-hydration="0">
    <pre data-node-hydration=1></pre>
    <path d="..." data-node-hydration="2"></path>
</svg>

The browser transforms that invalid svg into:

<svg ... data-node-hydration="0"></svg>
<pre data-node-hydration=1></pre>
<path d="..." data-node-hydration="2"></path>

We might need to use a different element than <pre> for placeholders in svgs

magikmw commented 2 months ago

I think this is happening in my project as well, but it's inconsistent. Sometimes the tags are set properly and the svg is displayed without issues.

MikhailNazarov commented 1 month ago

temporary solution that works for me: set an empty title:

Icon { title: "", width: 30, height: 30, fill: "red", icon: FiAlertTriangle }

this renders to:

<svg class="" height="30" width="30" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="red" stroke-width="2" data-node-hydration="18">
    <title data-node-hydration="19">
        <!--node-id20-->
        <!--#-->
    </title>
    <path d="..." data-node-hydration="21"></path>
    <line ..></line>
    <line ...></line>
</svg>