Coding, Insights, and Digital Discoveries 👩🏻‍💻

From Stay-at-Home Mom to a Developer After 50

Published on

Syntax Highlighting for Code Snippets in a React Application Using Prism-React-Renderer

syntax-highlighting-code-Snippets-in-react-application

The prism-react-renderer library is a React-based syntax highlighter powered by Prism.js, a widely-used library for syntax highlighting. It enables rendering highlighted code snippets in React applications with customizable themes and styles. This makes it ideal for presenting and styling code snippets in React projects, such as this developer-oriented blog.

Key Features of prism-react-renderer

  • Customizable Themes: You can choose from ready-made themes or create your own to style the syntax highlighting to fit your needs.

  • Language Support: Make sure to specify the correct programming language for accurate syntax highlighting.

  • Token Styling: Different parts of the code (like keywords, functions, and strings) are styled individually for clarity.

  • Flexible Rendering: The library uses a "render prop" approach, giving you full control over how the highlighted code is displayed in your application.

Highlight Component

The Highlight component is a wrapper provided by the prism-react-renderer library. It uses Prism.js under the hood to apply syntax highlighting to code.

Let’s look at an example of using prism-react-renderer through Sonner’s CodeBlock component implementation:

import Highlight, { defaultProps } from 'prism-react-renderer';

export const CodeBlock = () => {
    // some other code here...

    return (
        ....
        <Highlight {...defaultProps} theme={theme} code={children} language="jsx">
        {({ className, tokens, getLineProps, getTokenProps }) => (
          <motion.pre
            className={styles.wrapper}
            animate={{ height: bounds.height || initialHeight }}
            transition={{ type: 'easeOut', duration: 0.2 }}
          >
            <div className={`${className} ${styles.root}`} ref={setRef}>
              <div />
              {tokens.map((line, i) => {
                const { key: lineKey, ...rest } = getLineProps({ line, key: i });
                return (
                  <div key={lineKey} {...rest}>
                    {line.map((token, key) => {
                      const { key: tokenKey, ...rest } = getTokenProps({ token, key });
                      return <span key={tokenKey} {...rest} />;
                    })}
                  </div>
                );
              })}
            </div>
          </motion.pre>
        )}
      </Highlight>
      ....
    )
}

Props Passed to Highlight Component:

  • code: The code snippet to be highlighted. In this example, it’s passed as children.

  • language: The programming language of the code snippet (e.g., jsx, javascript, html, etc.). This ensures correct syntax highlighting.

  • theme: You can import or define themes for syntax highlighting. Each theme defines styles for specific token types (e.g., strings, keywords) and the overall appearance.

Render Prop Pattern:

The Highlight component uses the render function to allow customization of the highlighted code.

  • className: A CSS class corresponding to the chosen language and theme.

  • tokens: An array of arrays, where each sub-array represents a line of code, and each item within it represents a token (e.g., a keyword, variable, string, etc.).

  • getLineProps: A function that generates properties (e.g., keys and styling) for each line of code.

  • getTokenProps: A function that generates properties for each token within a line of code.

Token and Line Rendering:

  • Each line of code is iterated over using tokens.map(...).

  • Each line is rendered as a div, styled with getLineProps.

  • Each token within a line is rendered as a span, styled with getTokenProps.

More Examples of Rendering Highlighted Code

  1. Use Predefined Theme:
import React from "react";
import Highlight, { Prism } from "prism-react-renderer";
import theme from "prism-react-renderer/themes/nightOwl";

const code = `
function greet(name) {
  return 'Hello, ' + name;
}
`;

const CodeBlock = () => (
  <Highlight Prism={Prism} theme={theme} language="javascript" code={code}>
    {({ tokens, getLineProps, getTokenProps }) => (
      <pre style={{ padding: "10px", borderRadius: "5px", fontFamily: "monospace" }}>
        {tokens.map((line, i) => (
          <div {...getLineProps({ line, key: i })}>
            {line.map((token, key) => (
              <span {...getTokenProps({ token, key })} />
            ))}
          </div>
        ))}
      </pre>
    )}
  </Highlight>
);

export default CodeBlock;

  1. Use Custom Theme:
const customTheme = {
  plain: {
    backgroundColor: "#282C34",
    color: "#ffffff",
  },
  styles: [
    {
      types: ["keyword"],
      style: { color: "rgb(198, 120, 221)" },
    },
    {
      types: ["string"],
      style: { color: "rgb(152, 195, 121)" },
    },
  ],
};

  1. Use Dynamic Language selection
import React, { useState } from "react";
import Highlight, { Prism } from "prism-react-renderer";
import theme from "prism-react-renderer/themes/nightOwl";

const CodeRenderer = () => {
  const [language, setLanguage] = useState("javascript");
  const code = `
function add(a, b) {
  return a + b;
}
`;

  return (
    <div>
      <select onChange={(e) => setLanguage(e.target.value)} value={language}>
        <option value="javascript">JavaScript</option>
        <option value="python">Python</option>
        <option value="typescript">TypeScript</option>
      </select>
      <Highlight Prism={Prism} theme={theme} language={language} code={code}>
        {({ tokens, getLineProps, getTokenProps }) => (
          <pre style={{ padding: "10px", borderRadius: "5px", fontFamily: "monospace" }}>
            {tokens.map((line, i) => (
              <div {...getLineProps({ line, key: i })}>
                {line.map((token, key) => (
                  <span {...getTokenProps({ token, key })} />
                ))}
              </div>
            ))}
          </pre>
        )}
      </Highlight>
    </div>
  );
};

export default CodeRenderer;

Other Libraries

While Prism-react-renderer is a lightweight and powerful choice for syntax highlighting in React and Next.js applications, several other libraries may better suit specific project requirements.

For example, react-syntax-highlighter combines the strengths of Prism.js and Highlight.js, offering extensive language support and flexibility. This blog utilizes react-syntax-highlighter for all code snippet sandboxes.

Another noteworthy option is shiki, which uses VS Code’s syntax engine to deliver high-quality rendering and seamless integration with Next.js sites. For interactive scenarios where users need to write or edit code, CodeMirror stands out as a feature-rich editor with built-in syntax highlighting capabilities.

These alternatives each bring their own unique strengths, offering us developers a variety of options to choose from for our syntax highlighting needs.

← See All Posts