3

Question Desp: How could I highlight a custom syntax with prismjs in a react project?

I've created an extending syntax file (let's call it newlang) by following the guide.

And I know in prismjs there are three ways to highlight code:

  • highlightElement()
  • highlightAll()
  • highlight()

First, I tried to require my custom syntax file in my app.

import 'utils/highlight/prism-newlang';

Then, in my highlighting component,

  • Method 1: highlightElement() : ❌CANNOT get my code highlighting
import Prism from 'prismjs';

function CodeHighlight({ value, language }) {
  const codeEle = useRef(null);

  useEffect(() => {
    Prism.highlightElement(codeEle.current, false);
  }, []);

  return (
    <pre className={`language-${language}`}>
      <code ref={codeEle} className={`language-${language}`}>
        {value}
      </code>
    </pre>
  );
}
  • Method 2: highlightAll() : ❌CANNOT get my code highlighting
  • Method 3: highlight() : ✅CAN get my code highlighting
import { highlight, languages } from 'prismjs/components/prism-core';

function CodeHighlight({ value, language }) {
  const codeNode = useRef(null);

  useEffect(() => {
    const code = codeNode.current.textContent;
    const highlightHTML = highlightCode(code, language);
    codeNode.current.innerHTML = highlightHTML;
  });

  return (
    <pre className={`language-${language}`}>
      <code ref={codeNode} className={`language-${language}`}>
        {value}
      </code>
    </pre>
  );
}

I wonder what's the problem of Method 1 & 2. (Will be the matter of the loading order of custom syntax file?)

Gasin
  • 51
  • 2
  • 7

1 Answers1

3

For those who run into this issue in the future, I was able to get the first method working. In my case, I was calling Prism.highlight in the handleChange which was calling the function before the DOM was even updated with the internalText. I now use the useEffect hook which is invoked after the DOM is rendered, the trick is you need to declare the internalText as a subscribed parameter.

I have attached my Typescript component.

Hope this helps.

import React, { useState, ChangeEvent, useRef, useEffect } from 'react'
import './prism.css'
import Prism from "prismjs";

export function CodeBlockTile() {
  const language = "javascript"

  const codeElement = useRef<HTMLElement | null>(null);
  const [internalText, setInternalText] = useState<string>("")

  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
    setInternalText(event.target.value);
  };

  useEffect(() => {
    if (codeElement.current) {
      Prism.highlightElement(codeElement.current)
    }
  }, [internalText])


  return (
    <div>
      <textarea onChange={handleChange} value={internalText}>

      </textarea>
      <pre>
        <code ref={codeElement} className={`language-${language}`}>
          {internalText}
        </code>
      </pre>
    </div>
  )
}

kirkbyo
  • 61
  • 1
  • 5