avatarJennifer Fu

Summary

The provided content is a comprehensive guide on embedding the Prism Syntax Highlighter in React applications, detailing setup, usage, and customization for syntax highlighting across various languages and themes.

Abstract

The article "How To Embed a Prism Syntax Highlighter in React Apps" introduces Prism, a lightweight and robust JavaScript library for syntax highlighting, supporting 297 languages with a minimal core size of 2KB. It guides developers through setting up Prism in a Create React App environment, demonstrating how to include the necessary scripts and styles, wrap code in the appropriate HTML tags, and invoke Prism.highlightAll() to apply syntax highlighting. The guide also showcases examples for JavaScript, CSS, HTML, and JSON, and illustrates how to use different themes provided by Prism. Additionally, it explains the process of creating a new language definition for Prism, emphasizing the importance of adding language tests and example pages. The article concludes by affirming Prism's suitability for applications that require only syntax highlighting, acknowledging contributors, and promoting further engagement with the author's web development content.

Opinions

  • Prism is recommended for its lightweight nature and robust syntax highlighting capabilities, especially when only highlighting is needed.
  • The article expresses that Prism's support for a wide range of languages and its extensibility make it a versatile tool for developers.
  • The author suggests that Prism's theming system offers sufficient variety to cater to different aesthetic preferences for syntax highlighting.
  • The inclusion of test cases and example pages for new language implementations is presented as a best practice within the Prism community.
  • The author appreciates the contributions of Sushmitha Aitha and S Sreeram for implementing Prism features in Domino products, indicating a collaborative ethos in the web development community.
  • The article encourages readers to explore additional content and resources provided by the author, indicating a commitment to ongoing education and community engagement in web development.

How To Embed a Prism Syntax Highlighter in React Apps

Prism is a lightweight and robust JavaScript library that performs syntax highlighting for 297 languages

Photo by Fernando @cferdophotography on Unsplash

Introduction

An optical prism is a transparent optical element with flat, polished surfaces that are designed to refract light. A dispersive prism can be used to break white light up into its constituent spectral colors, i.e. colors of the rainbow.

Prism is a lightweight and robust JavaScript library that performs syntax highlighting for 297 languages. The minified and gzipped core is only 2KB, with each language definition adding roughly 300–500 bytes. It supports Edge, IE11, Firefox, Chrome, Safari, Opera, and most mobile browsers.

In a previous article, we have introduced Monaco Editor, a browser-based code editor that supports 78 languages, with syntax highlighting, autocompletion, autocorrection, diffing files, and many more advanced features.

If you only need syntax highlighting, Prism should be the way to go.

Set Up The Working Environment

We are going to embed a Prism Syntax Highlighter into the Create React App. The following command creates a React project:

% yarn create react-app react-prism
% cd react-prism

Install prismjs.

% yarn add prismjs

After the installation, prismjs becomes part of dependencies in package.json:

"dependencies": {
  "prismjs": "^1.29.0"
}

The work environment is ready.

Embed a Prism Inside React Apps

It takes a few steps to embed a Prism inside React Apps.

Step 1: Include prismjs and prism.css.

import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

Step 2: Wrap the code inside <pre> and <code> tags.

<pre><code class="language-xxxx">{code}</code></pre>

<pre> is a tag that defines preformatted text, and <code> is a tag that defines a piece of computer code. Prism requires code’s class name defined in the form of lang-xxxx or language-xxxx, where xxxx is the language alias.

Currently, Prism supports 297 languages. Here are some examples:

  • Markup: markup, html, xml, svg, mathml, ssml, atom, rss
  • CSS: css
  • JavaScript : javascript, js
  • JSON : json, webmanifest
  • Markdown: markdown, md
  • TypeScript: typescript, ts

Step 3: Call Prism.highlightAll() to highlight all syntaxes.

Prism.highlightAll() highlights all syntaxes. It fetches all the elements that have a language-xxxx class, and calls Prism.highlightElement() on each one of them. Prism.highlightElement() highlights the code inside a single element.

Here is the modified src/App.js to highlight one line of code, console.log(‘Hello, World!’);

import { useEffect } from 'react';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

function App() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);

  return (
    <pre>
      <code class="language-javascript">console.log('Hello, World!');</code>
    </pre>
  );
}

export default App;

Execute yarn start, and we see the JavaScript code’s syntax highlighting.

Image by author

Inspecting the elements in Web browser, we find out how the one line of code is tokenized and applied styles by token classes.

    <pre class="language-javascript" tabindex="0">
      <code class="language-javascript">
        console<span class="token punctuation">.</span>
        <span class="token function">log</span>
        <span class="token punctuation">(</span>
        <span class="token string">'Hello, World!'</span>
        <span class="token punctuation">)</span>
        <span class="token punctuation">;</span>
      </code>
    </pre>

Examples of JavaScript, CSS, HTML, and JSON Files

We present some code examples to demonstrate how syntax highlighting works for JavaScript, CSS, HTML, and JSON files.

Syntax highlighting for src/App.js

Here is the code that shows syntax highlighting for the Create React App’s src/App.js, where class is set to language-javascript:

import { useEffect } from 'react';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

function App() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);

  const code = `import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
`;

  return (
    <pre>
      <code class="language-javascript">{code}</code>
    </pre>
  );
}

export default App;

Execute yarn start, and we see the JavaScript code’s syntax highlighting.

Image by author

Syntax highlighting for src/index.css

Here is the code that shows syntax highlighting for the Create React App’s src/index.css, where class is set to language-css:

import { useEffect } from 'react';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

function App() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);

  const code = `{
    body {
      margin: 0;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
        'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
        sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }
    
    code {
      font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
        monospace;
    }
`;

  return (
    <pre>
      <code class="language-css">{code}</code>
    </pre>
  );
}

export default App;

Execute yarn start, and we see the CSS file’s syntax highlighting.

Image by author

Syntax highlighting for public/index.html

Here is the code that shows syntax highlighting for the Create React App’s public/index.html, where class is set to language-html:

import { useEffect } from 'react';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

function App() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);

  const code = `<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="utf-8" />
      <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <meta name="theme-color" content="#000000" />
      <meta
        name="description"
        content="Web site created using create-react-app"
      />
      <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
      <!--
        manifest.json provides metadata used when your web app is installed on a
        user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
      -->
      <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
      <!--
        Notice the use of %PUBLIC_URL% in the tags above.
        It will be replaced with the URL of the \`public\` folder during the build.
        Only files inside the \`public\` folder can be referenced from the HTML.
  
        Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
        work correctly both with client-side routing and a non-root public URL.
        Learn how to configure a non-root public URL by running \`npm run build\`.
      -->
      <title>React App</title>
    </head>
    <body>
      <noscript>You need to enable JavaScript to run this app.</noscript>
      <div id="root"></div>
      <!--
        This HTML file is a template.
        If you open it directly in the browser, you will see an empty page.
  
        You can add webfonts, meta tags, or analytics to this file.
        The build step will place the bundled scripts into the <body> tag.
  
        To begin the development, run \`npm start\` or \`yarn start\`.
        To create a production bundle, use \`npm run build\` or \`yarn build\`.
      -->
    </body>
  </html>
`;

  return (
    <pre>
      <code className="language-html">{code}</code>
    </pre>
  );
}

export default App;

You may have noticed that backticks (`) inside the template literal are escaped as \`.

Execute yarn start, and we see the HTML file’s syntax highlighting.

Image by author

Syntax highlighting for package.json

When showing the Create React App’s package.json, we know that class needs to be set to language-json. In addition, 'prismjs/components/prism-json' needs to be imported. The Prism core only includes limited languages to keep the size small. Additional language definitions are located at node_modules/prismjs/components.

Here is the code modified src/App.js:

import { useEffect } from 'react';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';
import 'prismjs/components/prism-json';

function App() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);

  const code = `{
    "name": "react-prism-editor",
    "version": "0.1.0",
    "private": true,
    "dependencies": {
      "@testing-library/jest-dom": "^5.14.1",
      "@testing-library/react": "^13.0.0",
      "@testing-library/user-event": "^13.2.1",
      "prismjs": "^1.29.0",
      "react": "^18.2.0",
      "react-dom": "^18.2.0",
      "react-scripts": "5.0.1",
      "web-vitals": "^2.1.0"
    },
    "scripts": {
      "start": "react-scripts start",
      "build": "react-scripts build",
      "test": "react-scripts test",
      "eject": "react-scripts eject"
    },
    "eslintConfig": {
      "extends": [
        "react-app",
        "react-app/jest"
      ]
    },
    "browserslist": {
      "production": [
        ">0.2%",
        "not dead",
        "not op_mini all"
      ],
      "development": [
        "last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
      ]
    }
  }
`;

  return (
    <pre>
      <code class="language-json">{code}</code>
    </pre>
  );
}

export default App;

Execute yarn start, and we see the JSON file’s syntax highlighting.

Image by author

Prism Supports Many Themes

The above examples use the default theme. In addition, Prism provides these themes: Coy, Dark, Funky, Okaidia, SolarizedLight, Tomorrow, and Twilight. Using src/index.css as an example, we can see how these themes look like.

The Coy Theme

Import the Coy theme in src/App.js:

import 'prismjs/themes/prism-coy.css';

Execute yarn start, and we see the syntax highlighting in the Coy theme.

Image by author

The Dark Theme

Import the Dark theme in src/App.js:

import 'prismjs/themes/prism-dark.css';

Execute yarn start, and we see the syntax highlighting in the Dark theme.

Image by author

The Funky Theme

Import the Funky theme in src/App.js:

import 'prismjs/themes/prism-funky.css';

Execute yarn start, and we see the syntax highlighting in the Funky theme.

Image by author

The Okaidia Theme

Import the Okaidia theme in src/App.js:

import 'prismjs/themes/prism-okaidia.css';

Execute yarn start, and we see the syntax highlighting in the Okaidia theme.

The SolarizedLight Theme

Import the SolarizedLight theme in src/App.js:

import 'prismjs/themes/prism-solarizedlight.css';

Execute yarn start, and we see the syntax highlighting in the SolarizedLight theme.

Image by author

The TomorrowNight Theme

Import the TomorrowNight theme in src/App.js:

import 'prismjs/themes/prism-tomorrow.css';

Execute yarn start, and we see the syntax highlighting in the TomorrowNight theme.

Image by author

The Twilight Theme

Import the Twilight theme in src/App.js:

import 'prismjs/themes/prism-twilight.css';

Execute yarn start, and we see the syntax highlighting in the Twilight theme.

Image by author

Are these enough themes for your application?

If not, you can get more themes:

Image made from https://github.com/PrismJS/prism-themes

How Prism Create a New Language

Prism provides a path to create a new language. You need to clone the repository, add your implementation, and build a new package for use.

We use JSON as an example to see the steps to build a new langauge.

Step 1: Add json into components.json.

Edit components.json to register the language, json, by adding it to the languages object.

{
  "core": {
    "meta": {
     "path": "components/prism-core.js",
     "option": "mandatory"
    },
    "core": "Core"
  },
  "themes": {
    ...
  },
  "languages": {
    "json": {
      "title": "JSON",
      "alias": "webmanifest",
      "aliasTitles": {
      "webmanifest": "Web App Manifest"
    },
    "owner": "CupOfTea696"
  "plugins": {
    ...
  }
}

Step 2: Create a component file.

Create a new file, such as components/prism-json.js, where json is the id of the language. The language id has to be unique and matches the regular expression /^[a-z][a-z\d]*(?:-[a-z][a-z\d]*)*$/.

// https://www.json.org/json-en.html
Prism.languages.json = {
 'property': {
  pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,
  lookbehind: true,
  greedy: true
 },
 'string': {
  pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
  lookbehind: true,
  greedy: true
 },
 'comment': {
  pattern: /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,
  greedy: true
 },
 'number': /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,
 'punctuation': /[{}[\],]/,
 'operator': /:/,
 'boolean': /\b(?:false|true)\b/,
 'null': {
  pattern: /\bnull\b/,
  alias: 'keyword'
 }
};

Prism.languages.webmanifest = Prism.languages.json;

The above object keys are token names, and each token is defined by a regular expression pattern, and whether it should be lookbehind and greedy. Each token can optionally have alias, and inside that defines another object literal.

Step 3: Add test cases for features.

It is recommended to add a test for every major feature of your language. For the example of JSON, test cases should be added to tests/languages/json/, and currently, there are 9 test cases:

Image by author

This is the content of tests/languages/json/boolean_feature.test:

true
false

----------------------------------------------------

[
 ["boolean", "true"],
 ["boolean", "false"]
]

----------------------------------------------------

Checks for booleans.

Step 4: Add an example page for the language.

Optionally, an example page can be created. The JSON example page is located at examples/prism-json.html. Here is the content:

<h2>Full example</h2>
<pre><code>{
    "data": {
        "labels": [
            "foo",
            "bar"
        ],
        "series": [
            [ 0, 1, 2, 3 ],
            [ 0, -4, -8, -12 ]
        ]
    },
    // we even support comments
    "error": null,
    "status": "Ok"
}</code></pre>

Conclusion

Prism is a lightweight and robust JavaScript library that performs syntax highlighting for 297 languages. The minified and gzipped core is only 2KB, with each language definition adding roughly 300–500 bytes. It supports Edge, IE11, Firefox, Chrome, Safari, Opera, and most mobile browsers.

We have explained how Prism works using React apps, and presented code examples to demonstrate how syntax highlighting works for JavaScript, CSS, HTML, and JSON files. A CSS file has been showcased with various themes. In the end, we use JSON as an example to describe how Prism creates a new language.

If you only need syntax highlighting, Prism is the best choice.

Thanks for reading.

Thanks Sushmitha Aitha and S Sreeram for implementing Prism features in Domino products.

Want to Connect?

If you are interested, check out my directory of web development articles.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Join our Discord community and follow us on Twitter, LinkedIn and YouTube.

Learn how to build awareness and adoption for your startup with Circuit.

Prism
Libraries
React
Programming
Web Development
Recommended from ReadMedium