Yew: How to render a string as unescaped HTML?

Created on 1 Jun 2020  路  7Comments  路  Source: yewstack/yew


Question

I would like to render Markdown in an app that I'm working on, so I wrote this (using the comrak crate for Markdown rendering):

html! {
    <div>
        { markdown_to_html("Hello, **涓栫晫**!", &ComrakOptions::default()) }
    </div>
}

Of course this just results in the HTML being escaped and output directly on the page.

What I've tried

I googled around to try to find how to output a raw string with Yew, but I didn't find anything.

PS. The Discord link seems to have expired :)

question

Most helpful comment

Yew currently doesn't support this - at least not directly.
However, thanks to the flexibility of references there's almost nothing you can't do.

Here's the code for a component that can be used to render raw html:

#[derive(Debug, Clone, Eq, PartialEq, Properties)]
struct RawHTMLProps {
  pub inner_html: String,
}

struct RawHTML {
    props: RawHTMLProps,
    node_ref: NodeRef,
}

impl Component for RawHTML {
    type Message = ();
    type Properties = RawHTMLProps;

    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
        Self { props, node_ref: NodeRef::default() }
    }

    fn update(&mut self, _: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, props: Self::Properties) -> ShouldRender {
        if self.props != props {
            self.props = props;
            true
        } else {
            false
        }
    }

    fn view(&self) -> Html {
        // create the parent element and store a reference to it
        html! {
            <div ref=self.node_ref.clone()/>
        }
    }

    fn rendered(&mut self, _first_render: bool) {
        let el = self.node_ref.cast::<Element>().unwrap();
        el.set_inner_html(&self.props.inner_html);
    }
}

The relevant code is in the rendered method which manually sets the innerHTML of the element.
You can use this component like this:

html! {
  <RawHTML inner_html="<span>Hello World</span>"/>
}

There's also a lower level approach to this which can be seen in the inner_html example but it's not quite as easy to understand what's going on there.


I think a component like this would make a great addition to the yewtil crate.

All 7 comments

Yew currently doesn't support this - at least not directly.
However, thanks to the flexibility of references there's almost nothing you can't do.

Here's the code for a component that can be used to render raw html:

#[derive(Debug, Clone, Eq, PartialEq, Properties)]
struct RawHTMLProps {
  pub inner_html: String,
}

struct RawHTML {
    props: RawHTMLProps,
    node_ref: NodeRef,
}

impl Component for RawHTML {
    type Message = ();
    type Properties = RawHTMLProps;

    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
        Self { props, node_ref: NodeRef::default() }
    }

    fn update(&mut self, _: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, props: Self::Properties) -> ShouldRender {
        if self.props != props {
            self.props = props;
            true
        } else {
            false
        }
    }

    fn view(&self) -> Html {
        // create the parent element and store a reference to it
        html! {
            <div ref=self.node_ref.clone()/>
        }
    }

    fn rendered(&mut self, _first_render: bool) {
        let el = self.node_ref.cast::<Element>().unwrap();
        el.set_inner_html(&self.props.inner_html);
    }
}

The relevant code is in the rendered method which manually sets the innerHTML of the element.
You can use this component like this:

html! {
  <RawHTML inner_html="<span>Hello World</span>"/>
}

There's also a lower level approach to this which can be seen in the inner_html example but it's not quite as easy to understand what's going on there.


I think a component like this would make a great addition to the yewtil crate.

Thanks for your help! I couldn't get the code you posted to work (dyn_cast doesn't seem to exist?), but I adapted the code you linked to into this, which works great:

#[derive(Debug, Clone, Eq, PartialEq, Properties)]
struct RawHTMLProps {
    pub inner_html: String,
}

struct RawHTML {
    props: RawHTMLProps,
}

impl Component for RawHTML {
    type Message = Msg;
    type Properties = RawHTMLProps;

    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
        Self { props }
    }

    fn update(&mut self, _: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, props: Self::Properties) -> ShouldRender {
        if self.props != props {
            self.props = props;
            true
        } else {
            false
        }
    }

    fn view(&self) -> Html {
        let div = web_sys::window()
            .unwrap()
            .document()
            .unwrap()
            .create_element("div")
            .unwrap();
        div.set_inner_html(&self.props.inner_html[..]);

        let node = Node::from(div);
        let vnode = VNode::VRef(node);
        vnode
    }
}

Right, sorry about that, it should've been dyn_into. You need to have JsCast in scope in order to use it ( use wasm_bindgen::JsCast).

Please refer to this comment that doesn't make me look quite as stupid.

That doesn't seem to work either:

no method named `dyn_into` found for struct `yew::html::NodeRef` in the current scope

Well this got very embarrassing for me, didn't it :sweat_smile:.
The method I was looking for is just cast. It's implemented on NodeRef itself.
The docs still use try_into but the function got renamed over a month ago.
I updated the code again and this time it should definitely work.

I was hastily trying to correct myself before so I didn't properly think about it. Sorry for wasting your time like that.

The docs still use try_into but the function got renamed over a month ago.
I updated the code again and this time it should definitely work.

I think the docs might still need to be updated for this

@kellpossible, totally forgot about that.
Fix: #1469

Thanks for bringing it up

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thienpow picture thienpow  路  3Comments

ghost picture ghost  路  5Comments

kellytk picture kellytk  路  3Comments

ghost picture ghost  路  4Comments

agausmann picture agausmann  路  3Comments