In this article, we will go over how you can make PrismJS code blocks editable and force PrismJS to re-render so the code blocks will be syntax highlighted again.
PrismJS can be used to add syntax that highlights code blocks on our website. For a personal project of mine, I needed to allow the user to paste in their own (docker-compose) yaml files. So, let’s take a look how we can let a user first edit a code block and then re-run PrismJS to add syntax highlighting.
So, our HTMl will look something like this.
Note: When I refer to “code block” I am referring to entire thing including the
pre
and thecode
tags.
<head><linkrel="stylesheet"type="text/css"href="stylesheets/prism.css"rel="stylesheet"/></head>...<preonPaste="setTimeout(function() {onPaste();}, 0)"id="editable"contenteditable><code id="yaml" class="language-yaml"></code></pre><script src="javascript/prism.js"></script>
In this file, we import the prism.css
stylesheet, there are many themes you can choose from in this example, but we will use the default theme. We will also import prism.js
. These are the two files required to use PrismJS.
<preonPaste="setTimeout(function() {onPaste();}, 0)"id="editable"contenteditable><code id="yaml" class="language-yaml"></code></pre>
Next, we create the code block on web page.
Note: the class on the
code
tag islanguage-yaml
.
To use PrismJS, we need to give the code a tag of a class of language-x
, where x is the language we want syntax highlighting for. You can find a full list of supported languages here.
To allow users to paste and edit the code block, we add contenteditable
to the pre
tag. The reason we add it to the pre
tag and not the code
tag is, when PrismJS runs the code, it will edit the code
block to include span
's and other html elements to do the syntax highlighting – this makes it a lot harder for the user to copy and paste when you edit the code tag as apposed to the pre
tag. The pre
tag also has onPaste="setTimeout(function() {onPaste();}, 0)"
, which means that after the user has pasted into the pre
tag, this function will be called. In this case we call a function called onPaste()
. However, we use a setTimeout
so that the browser has enough time to update the pre tag; else, the pre/code
tags will contain the previous text before the paste.
Now, the user can paste directly into the code block, but how do we force a re-render? Let’s take a look at the onPaste
function that is called every time the user pastes into our code block.
function onPaste() {const editable = document.getElementById("editable");const dockerCompose = editable.innerText;editable.innerHTML = '<code id="yaml" class="language-yaml"></code>';const yaml = document.getElementById("yaml");yaml.innerHTML = Prism.highlight(dockerCompose, Prism.languages.yaml, "yaml");}
So, first, we get the editable
element (our pre
tag). Next, we get the innerText of said element. This should be the new content the user wants to paste into the pre
tag. Sometimes, when you copy/paste into the code block, the old code
tag gets deleted so, just in case, we add the code
tag back in as this is where PrismJS will render our new YAML code. This is done with, editable.innerHTML = '<code id="yaml" class="language-yaml"></code>';
. This code replaces all the “children” of the pre
tag with the new code block. Next, we get the code
tag with id yaml
.
yaml.innerHTML = Prism.highlight(dockerCompose, Prism.languages.yaml, "yaml");
The main part of our code is actually what highlights our code. First, we pass the newly pasted yaml (stored in the dockerCompose
variable). Next, we tell Prism what language to use with Prism.languages.yaml
. Finally, we pass the language name which, in this case, is YAML. Then, we set this as the innerHTML
of the code
tag.
Note: The code in this project isn’t particularly clean as it’s mostly all in one file. I have done it this way to make the example a bit easier to follow when, in reality, you would most likely split it into multiple files.
Try adding any sample YAML code in the widget below.
Free Resources