Nuxt.js: v-html directive throws error if wrapper is other than `div` or `span`

Created on 30 Aug 2017  路  12Comments  路  Source: nuxt/nuxt.js

Like the title says, when I put some html source via the v-html: directive I get an ugly error and warning

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside \<p>, or missing <tbody>. Bailing hydration and performing full client-side render.

preceded by a supposedly list of mismatching elements (they do not mismatch after checking though).

After losing like 2 hours on this I found I am not alone as seen on this thread

It seems this error message only happens when using other wrappers than div or span.

// This works  without errors
...
<div v-html='myHtmlSource'></div>
...
// This fires the errors
...
<p v-html='myHtmlSource'></p>
...

EDIT:
Going deeper, nuxt.js goes crazier when trying to put a v-html rendered tag into a <nuxt-link> component... The components gets invisible or clunky (seems to appear at first reload then disappears magically)

// Don't try this at home
...
<nuxt-link to="/about">
<div v-html='myHtmlSource'></div>
</nuxt-link>
...

This question is available on Nuxt.js community (#c1360)
help-wanted

Most helpful comment

@Jonarod

What's in your HTML source?


This doesn't seem to be related to Nuxt, it's more a matter of HTML semantics. Vue, not Nuxt, is throwing the warning, and it also seems to be giving a pretty helpful error message:

This is likely caused by incorrect HTML markup, for example nesting block-level elements inside \

If we look deeper at the paragraph tag spec we'll see that the permitted content to go inside a paragraph tag is known as phrasing content.

Main takeaway --> We can't nest a <p> inside of <p>.

If your html string has paragraph tags and you're trying to use the v-html directive, you could be seeing those errors.

If your HTML string was this:

<p>hello world</p>

And then you tried to use it like this:

<p v-html='myHtmlSource'></p>

Your output would be this:

<p>
    <p>hello world</p>
</p>

That HTML would be invalid, not a bug with Nuxt.

All 12 comments

@Jonarod

What's in your HTML source?


This doesn't seem to be related to Nuxt, it's more a matter of HTML semantics. Vue, not Nuxt, is throwing the warning, and it also seems to be giving a pretty helpful error message:

This is likely caused by incorrect HTML markup, for example nesting block-level elements inside \

If we look deeper at the paragraph tag spec we'll see that the permitted content to go inside a paragraph tag is known as phrasing content.

Main takeaway --> We can't nest a <p> inside of <p>.

If your html string has paragraph tags and you're trying to use the v-html directive, you could be seeing those errors.

If your HTML string was this:

<p>hello world</p>

And then you tried to use it like this:

<p v-html='myHtmlSource'></p>

Your output would be this:

<p>
    <p>hello world</p>
</p>

That HTML would be invalid, not a bug with Nuxt.

Hey @jsonberry thanks for your quick reply!

If we look deeper at the paragraph tag spec we'll see that the permitted content to go inside a paragraph tag is known as phrasing content.
Main takeaway --> We can't nest a \

inside of \

.

I trust you, however the project I have is a Vue.js I am translating to Nuxt.js. So I basically copy-pasted <template> and <style> tags and just tweaked some <script> (mainly I took advantage of asyncData hook and implemented Vuex: that's it). In the original project using Vue.js these errors do not exist and the html markup is strictly the same...

I am not to understand this :

Your output would be this:

<p>
   <p>hello world</p>
</p>

That HTML would be invalid, not a bug with Nuxt.

I implemented a basic fiddle showing there is no error with pure Vue.js. (I get the same result locally in dev mode)

Now, the very same component in Nuxt.js throws an error.

I confirm this happens only on nuxt.js as the error throws only on server-side rendering: when navigating to the page containing the v-html (thus served by the client) the error does not exist. Also, there is no error after hot-reloading, the error only occurs after page refresh served by the server.

Your fiddle gives no errors because _you're not rendering anything via the server_, that's all client side.

The DOM nodes are being rewritten, and this is likely due to incorrect HTML semantics. Check this out:

banners_and_alerts_and_nestedp_html_and_document

This is in Chrome, with a bare-bones HTML document. Check out the source, and then check out how the actual DOM nodes have been written. See how this correlates to The client-side rendered virtual DOM tree is not matching server-rendered content? This is strictly HTML.

In your original Vue project are you rendering anything on the server? If not, that is why you're not seeing any errors. Now that you're using the same information with Nuxt, it _is_ attempting to match server rendered content with client-side rendered content, and there's a mismatch.

Because of the mismatch, Vue can not hydrate the DOM correctly. That's why you see Bailing hydration and performing full client-side render.

Can you please share an example of an HTML source that is causing you the error?

Sorry I am very new at SSR, and I just can't get my head through this issue.
Indeed my previous implementation was client-side only, it was never server-rendered :)

Now, here you have my complete .vue file causing the error:

// Original code leading to error
<template>
  <div>
      <p v-html="htmlSource"></p>
  </div>
</template>

<script>
export default {
  asyncData ({ req }) {
    return {
      htmlSource: `<h1>This is my title</h1>`
    }
  }
}
</script>

<style>
</style>

I understand the error message as it is not semantically correct to include <h1> tags into <p> tags given HTML5 specs. However, I do NOT understand where this validation is done: Nuxt.js ?
Vue.js ? nor why the server tries to "rewrite" or "validate" what I believe it should NOT?
I call it a bug as I think it is my responsibility as a developer to decide if I want to comply with some specs or if I think it is not necessary for my use-case.

For my use-case, the htmlSource will be provided by users writing blog posts in Markdown. I believe they will not refer to HTML5 specs to rationalize their semantics before writing, and they should not. So, all in all, users WILL create content that COULD potentially end-up like p > blockquote > p > h1.

Finally, look here :

// simulating the same output manually without v-html
<template>
  <div>
      <p> First paragraph
        <p>Second paragraph</p>
        <h1>H1 in a p tag <p>P tag in a h1</p></h1>
      </p>
  </div>
</template>

<script>
export default {
}
</script>

<style>
</style>

The above script works fine even when server-rendered.

Stranger is this :

// using v-html but from a span tag
// No errors ??
<template>
  <div>
      <span v-html="htmlSource"></span>
  </div>
</template>

<script>
export default {
  asyncData ({ req }) {
    return {
      htmlSource: `<div>This is a div in a span</div>`
    }
  }
}
</script>

<style>
</style>

div inside span is not valid HTML5. Still, no error message even when server-rendered...

That being said, my conclusion is that the error message does not relate to a coherent validation, rather it raises the fact that Nuxt.js oddly tells me it doesn't accepts p tags as root if v-html directive is used.


On a side-note, after trying this approach with Next.js (original inspiration for Nuxt.js): this validation does not seem to happen:

// react.js equivalent for <p v-html="htmlSource"></p> in Vue.js
<p dangerouslySetInnerHTML={{__html: props.htmlSource}}></p>

// works fine in Next.js environment

Objectively, for me it is not a big deal. I just replaced the p tag by a div and we're done.
So if someone wants to close this off, no problem but I think it should be documented somewhere for beginners like me. :)

@Jonarod I'm pretty sure you're right, that a div inside of a span is invalid. _That_ smells a little like a bug to me. 馃悰 馃悶

馃槙

For what it's worth, I think the warnings are being thrown from a Vue library and not specifically related to Nuxt.

i also have problem with v-html

<template lang="pug">
    div
      header
       h1 project news line
       nav
        nuxt-link(to='/') home
        nuxt-link(to='/about') about 
        nuxt-link(to='/contacts') call me
      .wrapper
       form(@submit="postMesseage")
        section.container
         md-input-container
          label With label
          md-input(placeholder='Head',  v-model="name", type='text', )

          button(type="submit") add news
         .quill-editor(:content='content', @change='onEditorChange($event)', @blur='onEditorBlur($event)', @focus='onEditorFocus($event)', @ready='onEditorReady($event)', v-quill:myquilleditor='editorOption', v-model="newMessage")

       section#message(v-for='(message, index) in messages')

         button( @click="deleteRow(index)" v-bind:id="message._id") 褍写邪谢懈褌褜
         nuxt-link(:to="{ path: '/edite/'+message._id,  params: { id: message._id } }") 
          button 袪械写邪泻褌懈褉芯胁邪褌褜
         h2 
          nuxt-link(:to="{ path: '/news/'+message._id,  params: { id: message._id } }" ) {{ message.name }}

           div(v-html="message.content") {{ message.content }}




    </template>

if remove div(v-html="message.content")

all okey ;

response from server

{"total":1,"limit":10,"skip":0,"data":[{"_id":"59acc2b18f9b35143f4b3ce8","content":"<p><s>asdasdasd</s></p>","name":"asdasdasdasd","createdAt":"04/09/2017","updateAt":"04/09/2017"}]}

if exclude html tags from database , then okey too... why v-html not worked ?

@andysay Did you try removing the {{message.content}} inside your v-html tag ? I don't think you need to put anything more than your v-html directive.

@Jonarod if npm run build after start , error no have.

only with npm run dev

I'm closing this issue because it's not related to nuxt source code, but Vue.js hydration. You can still comment on this issue for the rest of the community.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vadimsg picture vadimsg  路  3Comments

o-alexandrov picture o-alexandrov  路  3Comments

pehbehbeh picture pehbehbeh  路  3Comments

nassimbenkirane picture nassimbenkirane  路  3Comments

gary149 picture gary149  路  3Comments