highlight.js icon indicating copy to clipboard operation
highlight.js copied to clipboard

highlight.js , ckededitor5 , next.js Element previously highlighted. To highlight again, first unset `dataset.highlighted`.

Open uchar opened this issue 1 year ago • 5 comments
trafficstars

I'm using Next.js and ckeditor for generating content . code is :

'use client'
import React, { useEffect, useRef } from 'react'
import Box from '@mui/material/Box'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import '@/common/components/Editor/Content.css'
import 'highlight.js/styles/ascetic.css'

interface ParseContentProps {
  content: string
}

export const ParseContent = ({ content }: ParseContentProps) => {
  const contentRef = useRef<HTMLDivElement>(null)

  const sanitizedContent = DOMPurify.sanitize(content)

  useEffect(() => {
    const codeBlocks = contentRef.current?.querySelectorAll('pre code')
    codeBlocks?.forEach((block) => {
      hljs.highlightElement(block as HTMLElement)
    })
  }, [sanitizedContent])

  return (
    <div className="ck-content">
      <Box
        ref={contentRef}
        dangerouslySetInnerHTML={{
          __html: sanitizedContent,
        }}
      />
    </div>
  )
}

But it doesn't highlight anything and keep giving error :

Element previously highlighted. To highlight again, first unset `dataset.highlighted`. <code class=​"language-javascript hljs" data-highlighted=​"yes">​…​</code>​

if I use

'use client'
import React, { useEffect, useRef } from 'react'
import Box from '@mui/material/Box'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import '@/common/components/Editor/Content.css'
import 'highlight.js/styles/ascetic.css'

interface ParseContentProps {
  content: string
}

export const ParseContent = ({ content }: ParseContentProps) => {
  useEffect(() => {
    hljs.highlightAll()
  }, []) // Dependency on sanitizedContent to re-run on change

  return (
    <div className="ck-content">
      <pre>
        <code className="language-javascript">{'let a=5;'}</code>
      </pre>
    </div>
  )
}

It starts working , not sure what is causing the first example not working does it have something to do with SSR ? not sure what I need to change , first one seems fine to me , Is this a highligh.js bug ?

uchar avatar Sep 28 '24 16:09 uchar

Element previously highlighted.

There is no reason to highlight an element twice.

does it have something to do with SSR

That would make sense, if it was highlighted server-side it does not need to be re-highlighted on the client - it's already highlighted.

joshgoebel avatar Sep 28 '24 16:09 joshgoebel

@joshgoebel yes but the real problem is not the warning . highlight doesnt work in first case ,I guess it only do it on server side and completely ignore client side . what's the solution here ?

uchar avatar Sep 28 '24 20:09 uchar

the output is really weird , if I refresh the page , no highlight image

but if I change the route from another page to this one highlight start working image

uchar avatar Sep 28 '24 21:09 uchar

I figure out that the error about previously highlited was not about SSR but about reactStrictMode , which according to documents :

React 18 enables Strict Mode, which triggers an additional render cycle during development to help identify side effects

If I disable it in next.config.js , no warning will be shown . But the main problem still remains, when I refresh the page there is no highlighting , but if I move between pages I have highlighting

uchar avatar Sep 28 '24 21:09 uchar

I would suggest modifying your first example to do exactly what is suggested:

first unset dataset.highlighted.

So write custom Javascript to do that (unset it) BEFORE you call highlightAll... then everything should just work.

joshgoebel avatar Sep 28 '24 21:09 joshgoebel

is this issue still open? I would like to help. Please assign it to me

Shrutikaghule avatar Oct 23 '24 22:10 Shrutikaghule

yes but the real problem is not the warning . highlight doesnt work in first case ,I guess it only do it on server side and completely ignore client side . what's the solution here ?

This sounds like a problem with your config/framework/server-side generation, etc. So far I've heard or seen nothing that sounds like a library bug. If someone can provide a jsfiddle that shows this issue (without React or other confounding factors).


Here is how the library behaves:

  • When Highlight.js highlights an element (highlightElement) it marks the element as highlighted via dataset.highlighted
  • It will refuse to highlight any element already flagged with dataset.highlighted

This is the current expected behavior of the library, and considered correct.

If you're doing something [React, etc] on the client-side that somehow replaces ALL of the block's HTML content - but does NOT remove dataset.highlighted then you will need to remove that manually - before asking Highlight.js to re-highlight the block.


The advice above to disable reactStrictMode sounds like good advice - or perhaps it has a hook to add behavior to it - in which case you might need to add code there to unset dataset.highlighted.

joshgoebel avatar Oct 24 '24 21:10 joshgoebel

is this issue still open? I would like to help.

What do you think the fix is? It's not clear yet to me that anything needs to be changed.

joshgoebel avatar Oct 24 '24 22:10 joshgoebel

Closing for inactivity.

joshgoebel avatar Nov 29 '24 17:11 joshgoebel