DEV Community


Posted on • Updated on

Html to render function

Hey, my name is Shaked, and I want to tell you how to convert boring HTML to Vue/react render function.
There is often this issue with legacy content or content you want to load in general, which has an HTML format, and as we all know, neither Vue nor Rack likes to load HTML directly. Both frameworks can do it; for instance, Vue/Nuxt has v-html, which can let you place html inside, but the issue with that is security and bad practice. Also, you are kind of out of luck if you want to modify HTML on the fly; for example, you want to change all A tags to be a nuxt-link tag or change the links that have Twitter inside in the href of the tag to be twitter-component to load your custom component.
So I built a solution; here is the git repo -> will very appreciate if you can start it. Also you can look at the Youtube video
This repository has a couple of files. The first is a python docker container which will help you convert the content. This container is a flask server that runs a miniature python version.
This server/container will start from the file.
There is an HTML example and JSON file to show the result. Also, a Vue file to show you an example of how to use it. Please note that in the Vue example, I am using Vuex to get the content, but you can pass it anyway to like props, etc.
So let's see the code here

@app.route('/', methods=['POST'])
def index(): # html_content is a string 
    html_content = request.form.get('html')
        html = HtmlConverter()

        return {"success": "Successfully got render func.", "data": html.soupToJson() }
    except Exception as e:
        return {"error": "can not convert this to render func" }
Enter fullscreen mode Exit fullscreen mode

So very simple flask server getting the post html parameter and convert it using my custom HtmlConverter object. to more info about this object go to

Vue example with render function

const imgComponent = () => import('./Image')
const videoComponent = () => import('./Video')
const audioComponent = () => import('./Audio')
const youtubeComponent = () => import('./Youtube')
const twitterComponent = () => import('./Twitter')
const facebookComponent = () => import('./Facebook')
const taboolaComponent = () => import('~/components/taboola')
export default {
  components: {
    'img-component': imgComponent,
    'video-component': videoComponent,
    'audio-component': audioComponent,
    'youtube-component': youtubeComponent,
    'twitter-component': twitterComponent,
    'facebook-component': facebookComponent,
    'taboola-component': taboolaComponent
  computed: { ...mapState('articles', ['content']) },
  methods: {
    handleContent (content, h) {
      if (typeof content === 'string' || content instanceof String) {
        return content
      if (Array.isArray(content) && content.length > 0) {
        return => {
          // console.log('%c currentElement: ' + el.tag + ' attrs: ' + el.attrs + ' content: ' + el.content, 'color: green; font-weight: bold')
          if (typeof el === 'string' || el instanceof String) {
            return el
          const attrs = { attrs: { ...el.attrs } /* style: { order: '1' } */ }
          if (Array.isArray(el?.content) && el?.content?.length > 0) {
            return h(el.tag, {}, this.handleContent(el.content, h))
          if (
            el.tag === 'iframe' &&
          ) {
            return h('facebook-component', { props: { item: el.attrs.src } })
          if (el.tag === 'img') {
            attrs.on = {
              click: (event) => { // add custom event
          return h(el.tag || 'span', attrs, el.content)
      return ''
  render (createElement) {
    const content = [...this.content] // create copy to avoid error in reactive node
    return createElement('div', {}, this.handleContent(content, createElement))
Enter fullscreen mode Exit fullscreen mode

Top comments (0)