Invalid HTML inside `dangerouslySetInnerHTML` breaks the page.
Bug report
Describe the bug
If invalid HTML is added to dangerouslySetInnerHTML, Next.js will output a blank page without providing any feedback. This can be hard to track when working with a CMS provider or markdown files.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Clone https://github.com/lfades/nextjs-inner-html-bug
- Run
yarn && yarn devornpm i && npm run dev - See that
pages/index.jsis a blank page with no errors
Expected behavior
Invalid HTML inside dangerouslySetInnerHTML should throw and/or let the user know that there's something wrong.
The demo also has an index.html and index.js in the root directory that shows how the same code works in React alone, it doesn't produce an error either, but it shows the content.
Hey @lfades is it okay if I take this issue up?
I was able to reproduce the issue locally and noticed that the reason the page goes blank is because dangerouslySetInnerHTML seems to be auto closing the open tag while wrapping any HTML/Scripts etc.. underneath inside of the tag.
This does not cause the page to go blank if that invalid html tag is a
I think the right behavior would be to ensure that the next.js scripts don't end up wrapped inside of the invalid tag so that the JS can execute and any valid content can still render on the page.
What are your thoughts, i'll attach screenshots for reference...
Open tag will autoclose with all markup and scripts underneath the open tag wrapped inside of it

Same issue with
NOT an issue with a open markup tag

@lfades or anyone else..
I tried to run a forked/cloned version of next locally and have it point to the example app but I keep running into a mismatch react issue.
I tried to work through it but am stuck, any thoughts?
@TatisLois Follow the steps here to setup the Next.js repo: https://github.com/vercel/next.js/blob/canary/contributing.md
Once you run yarn dev inside the root directory (which compiles the Next.js packages), you can change your package.json and point it to the next package: https://github.com/vercel/next.js/blob/canary/contributing.md#running-your-own-app-with-locally-compiled-version-of-nextjs
@TatisLois Follow the steps here to setup the Next.js repo: https://github.com/vercel/next.js/blob/canary/contributing.md
Once you run
yarn devinside the root directory (which compiles the Next.js packages), you can change yourpackage.jsonand point it to thenextpackage: https://github.com/vercel/next.js/blob/canary/contributing.md#running-your-own-app-with-locally-compiled-version-of-nextjs
~~I followed those steps and is how I ran into the issue. I’ll wipe the repo clean and try again from scratch, thanks!~~
got it working - thanks
I'll take a look at this issue as well. I think the responsibility of putting in valid html in dangerouslySetInnerHTML is on the user, but I think I have a solution for outputting an error if the user does so. (Ping @lalmqvist)
I don't have time to continue on this issue, so if anyone else wants to continue - feel free to do so!
My idea is to validate the HTML with perhaps html-validator package and logging the error to the console. I think adding something similiar to this in Main component could work:
export function Main() {
const { inAmpMode, html, docComponentsRendered } = useContext(
DocumentComponentContext
)
+ const [invalidHtmlError, setInvalidHtmlError] = useState()
docComponentsRendered.Main = true
+ useEffect(() => {
+ checkHtml()
+ })
+ const checkHtml = async () => {
+ try {
+ await htmlValidator(html)
+ } catch (error) {
+ setInvalidHtmlError(error)
+ }
+ }
if (inAmpMode) return <>{AMP_RENDER_TARGET}</>
+ if (invalidHtmlError) {
+ Log.error(
+ "There's an error with your HTML",
+ JSON.stringify(invalidHtmlError)
+ )
+ }
return <div id="__next" dangerouslySetInnerHTML={{ __html: html }} />
}
I also had this problem when allowing user generated HTML. If you wrap the dangerously set HTML code using the sanitize package linked below - it auto-fixes this broken HTML problem for you.
https://www.npmjs.com/package/sanitize-html
<div dangerouslySetInnerHTML={{ __html: (sanitizeHtml(yourHtmlStringHere, {
allowedTags: ['*'],
allowedAttributes: {'*': [ '*' ]},
allowedAttributes: { '*': ["*"]},
allowedIframeHostnames: ['*']
})) }}
/>
I'll take this one on.
Hey, is there any progress on the issue?
If there is no one that is not taking this on, I'll be ready to take this on.
cc @Timer @Christopher-Stevers @lfades
If there is no progress on this issue,please assign this issue to me
Can't reproduce on latest commit. I see the heading but not the subtitle because of wrong tag. But the page works fine.
Hello, can I fix this bug, if no one is working on it? @samcx @lfades
@Mbistami Nobody is! Feel free to open a PR 🙇🏼
@samcx should we use some library to validate the HTML or can't add packages I'm very new to contributing in next and I think adding html-validator can help fixing it but I'm not sure if its okay to install a whole library for this only bug?
Hmm we should already have something like this.
If you use the command pnpm new-test, it'll create a folder with a test file like this →
import { nextTestSetup } from 'e2e-utils'
describe('test-test', () => {
const { next } = nextTestSetup({
files: __dirname,
})
// Recommended for tests that check HTML. Cheerio is a HTML parser that has a jQuery like API.
it('should work using cheerio', async () => {
const $ = await next.render$('/')
expect($('p').text()).toBe('hello world')
})
// Recommended for tests that need a full browser
it('should work using browser', async () => {
const browser = await next.browser('/')
expect(await browser.elementByCss('p').text()).toBe('hello world')
})
// In case you need the full HTML. Can also use $.html() with cheerio.
it('should work with html', async () => {
const html = await next.render('/')
expect(html).toContain('hello world')
})
// In case you need to test the response object
it('should work with fetch', async () => {
const res = await next.fetch('/')
const html = await res.text()
expect(html).toContain('hello world')
})
})
I see, but I coulnd't find a way to get the HTML to validate It tried to implement it on Main in _document.tsx but seems confusing should I maybe add the handling on the Document class?
@Mbistami I think we should try to validate what you're seeing is this error itself. Do you have a 
@samcx
https://github.com/lfades/nextjs-inner-html-bug
@Mbistami That 
I tested this with app routes, and it works fine. The issue with the provided code from @Mbistami in the repo https://github.com/lfades/nextjs-inner-html-bug seems to be that it contains invalid style properties mixed into the HTML:
const HTML =
<div>
<h1>This is a title</h1>
<style>
<h2>This is a subtitle</h2>
</div>
After removing the invalid
Closing because this has become stale!
If this issue arises, feel free to re-submit an issue via the bug report.
This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.