Highlight.js with React

Highlight.js with React

By Mike Lewis

Using highlight.js in React is pretty straight forward if the content that you're rendering is just static. However, I usually find that I want to highlight dynamic HTML code that I'm rendering from a CMS so I'm using dangerouslySetInnerHTML. In that case it's not totally clear how to apply the highlighting to the inner HTML. In this article I will go over how to do that.

 

Installation

Of course you'll need to install highlight.js:

npm install highlight.js

or

yarn add highlight.js

You will also need to include the CSS for highlight.js in your project somehow. I'm using Next.js so I just link the CSS in a custom _document.js.

 

Component

I created a component called Highlight to wrap this functionality. It takes one prop and that is the HTML that I'm rendering.

The render method is pretty straight-forward:

render() {
    const { content } = this.props;
    return (
        <div ref={this.nodeRef} dangerouslySetInnerHTML={{ __html: content }} />
    );
}

 

All I am doing is rendering that HTML with dangerouslySetInnerHTML and setting up a ref to the wrapping div that I'm going to use later to highlight.

In the constructor I need to do the ref setup:

constructor(props) {
    super(props);
    this.nodeRef = React.createRef();
}

Next I create a method to use that ref and actually call highlight.js on any nodes that I choose:

highlight = () => {
    if (this.nodeRef) {
        const nodes = this.nodeRef.current.querySelectorAll('pre');
        nodes.forEach((node) => {
            hljs.highlightBlock(node);
        });
    }
}

In the above I am just applying highlight.js to any blocks wrapped in a <pre> tag, which is what I use in the CMS to indicate that this should be highlighted.

And finally we just need to call the highlight method when we're ready. All together the component looks like this:

import React, { Component } from 'react';
import hljs from 'highlight.js/lib/highlight';
import javascript from 'highlight.js/lib/languages/javascript';

hljs.registerLanguage('javascript', javascript);

class Highlight extends Component {
    constructor(props) {
        super(props);
        this.nodeRef = React.createRef();
    }

    componentDidMount() {
        this.highlight();
    }

    componentDidUpdate() {
        this.highlight();
    }

    highlight = () => {
        if (this.nodeRef) {
            const nodes = this.nodeRef.current.querySelectorAll('pre');
            nodes.forEach((node) => {
                hljs.highlightBlock(node);
            });
        }
    }

    render() {
        const { content } = this.props;
        return (
            <div ref={this.nodeRef} dangerouslySetInnerHTML={{ __html: content }} />
        );
    }
}


export default Highlight;