Vue tree renderer

from Red Blob Games
3 Nov 2018

On the Vue discord someone mentioned wanting to display sanitized html. I was wondering if this could be done with a recursive vue element running on a parse tree.

Let’s say we want to render something like <b>blabla</b> asdadasd <b><i>bla</i>bla</b> and we already have a parse tree version of it (note: I didn’t implement anything here to actually parse the html – I’m assuming you have that already):

let parsed = [
    'span',
    ['b', 'blabla'],
    ' asdadasd ',
    ['b', ['i', 'bla'], 'bla']
];

A render function can inspect that parse tree and output the right type of node, but only allows some tags:

Vue.component('v-html-subset', {
    functional: true,
    props: ['allowed', 'tree'],
    render(h, context) {
        function traverse(tree) {
            let [type, ...children] = tree;
            return h(type, children.map(child => typeof child === 'string'? child : traverse(child)));
        }
        return traverse(context.props.tree);
    }
});

Let’s make an interactive demo:

new Vue({
    el: "#vue",
    data: {tree: JSON.stringify(parsed, null, 4)},
    template: `
      <div>
        <textarea cols="40" rows="15" v-model="tree"/>
        <p id="output">
          <v-html-subset v-bind:tree="parsed"/>
        </p>
      </div>`,
    computed: {
      parsed() {
        try {
          return JSON.parse(this.tree);
        } catch (e) {
          return ['b', 'parse error'];
        }
      },
    },
});

Try it out:

Sanitization could be done at the parsing step, or the component could check the types and output span for any disallowed tags.

Email me at , or tweet to @redblobgames, or post a public comment: