How to add code snippets using TinyMCE and Prism.js

Code snippets are small blocks of reusable code, it is common for developers to copy and paste code they've already written, code from their company's code base, open source code, and answers on stack overflow. If you have a blog where you share knowledge with other developers, you may probably tested a lot of WYSIWYG editors that provide an easy way to edit your articles, they accomplish their basic task however they doesn't work pretty well with code snippets. Problem that the people that write with markup doesn't have, however what about for those that use HTML ? Fortunately, someone listened our prayers and TinyMCE decided to provide support for code snippets with the help of Prism.js. Prism is a lightweight, extensible syntax highlighter, built with modern web standards in mind. It’s used in thousands of websites, including some of those you visit daily.

Talk is cheap. Show me the code.

- Linus Torvalds , founder of Linux

How to add a snippet

To add code snippets to your content, you can use the codesample plugin (usually included in the community version). To enable this plugin, you only need to provide the name of the plugin "codesample" in the plugins property of the initialization object and add the action button in the toolbar, identified with the same name "codesample":

tinymce.init({
    selector: 'textarea',
    plugins: 'codesample',
    toolbar: 'codesample'
});

Once you add the codesample plugin and the action button in the toolbat, your tinymce should show the new button:

TinyMCE Code sample button

Note

This plugin can be used from the version 4.3 of TinyMCE. Therefore it was in "test stage" and there were several bugs and modifications, however most of them were quickly solved e.g you couldn't load more than 10 languages to highlight.

As you know, Prism.js encourages good author practices. Other highlighters encourage or even force you to use elements that are semantically wrong, like <pre> (on its own) or <script>. Prism forces you to use the correct element for marking up code: <code>. On its own for inline code, or inside a <pre> for blocks of code. In addition, the language is defined through the way recommended in the HTML5 draft: through a language-xxxx class. With TinyMCE, this language can be set through a select element shown in the code input dialog. You can add new languages at the initialization by setting the codesample_languages property:

tinymce.init({
    selector: 'textarea',
    plugins: 'codesample',
    codesample_languages: [
        {text: 'HTML/XML', value: 'markup'},
        {text: 'JavaScript', value: 'javascript'},
        {text: 'CSS', value: 'css'},
        {text: 'PHP', value: 'php'},
        {text: 'Ruby', value: 'ruby'},
        {text: 'Python', value: 'python'},
        {text: 'Java', value: 'java'},
        {text: 'C', value: 'c'},
        {text: 'C#', value: 'csharp'},
        {text: 'C++', value: 'cpp'}
    ],
    toolbar: 'codesample'
});

Now if you click on the codesample button in TinyMCE, then you should see the code input dialog:

TinyMCE Code Sample Input

All unsafe characters for the generated HTML (like a HTML snippet inside) will be automatically escaped to its html symbol, so the HTML generated by TinyMCE with a html snippet should look like:

<p>Span tag in HTML:</p>
<pre class="language-html"><code>&lt;span&gt;Hello World&lt;/span&gt;</code></pre>
<p>Hello World !</p>

And the user interface:

TinyMCE and Prism.js

Customize Prism style

By default TinyMCE uses the default theme of Prism included by default in the plugin. By customizing the codesample_content_css option at the initialization with the path to the custom CSS file of Prism.css you can use your own theme e.g the Our Code World snippet highlighting (Okaidia):

tinymce.init({
    selector: 'textarea',
    plugins: 'codesample',
    codesample_languages: [
        {text: 'HTML/XML', value: 'markup'},
        {text: 'JavaScript', value: 'javascript'},
        {text: 'CSS', value: 'css'},
        {text: 'PHP', value: 'php'},
        {text: 'Ruby', value: 'ruby'},
        {text: 'Python', value: 'python'},
        {text: 'Java', value: 'java'},
        {text: 'C', value: 'c'},
        {text: 'C#', value: 'csharp'},
        {text: 'C++', value: 'cpp'}
    ],
    toolbar: 'codesample',
    // Custom CSS file
    codesample_content_css: "http://ourcodeworld.com/material/css/prism.css",
});

And as result:

Custom CSS Prism.js TinyMCE code sample

Change code input dimensions

You can change the dimensions of the dialog in which you enter the code by changing the codesample_dialog_width and codesample_dialog_height:

tinymce.init({
    selector: 'textarea',
    plugins: 'codesample',
    codesample_languages: [
        {text: 'HTML/XML', value: 'markup'},
        {text: 'JavaScript', value: 'javascript'},
        {text: 'CSS', value: 'css'},
        {text: 'PHP', value: 'php'},
        {text: 'Ruby', value: 'ruby'},
        {text: 'Python', value: 'python'},
        {text: 'Java', value: 'java'},
        {text: 'C', value: 'c'},
        {text: 'C#', value: 'csharp'},
        {text: 'C++', value: 'cpp'}
    ],
    toolbar: 'codesample',
    // Custom dimensions
    codesample_dialog_height: 400,
    codesample_dialog_width: 600
});

Custom languages list

So you do not have to look the list of supported Languages by Prism and then create the object with the language identifier and name by yourself, we provide you the list of all supported languages by Prism.js to use in the codesample_languages property of TinyMCE:

tinymce.init({
    selector: 'textarea',
    plugins: 'codesample',
    toolbar: 'codesample',
    codesample_languages: [
        {text:'HTML/XML',value:'markup'},
        {text:"XML",value:"xml"},
        {text:"HTML",value:"html"},
        {text:"mathml",value:"mathml"},
        {text:"SVG",value:"svg"},
        {text:"CSS",value:"css"},
        {text:"Clike",value:"clike"},
        {text:"Javascript",value:"javascript"},
        {text:"ActionScript",value:"actionscript"},
        {text:"apacheconf",value:"apacheconf"},
        {text:"apl",value:"apl"},
        {text:"applescript",value:"applescript"},
        {text:"asciidoc",value:"asciidoc"},
        {text:"aspnet",value:"aspnet"},
        {text:"autoit",value:"autoit"},
        {text:"autohotkey",value:"autohotkey"},
        {text:"bash",value:"bash"},
        {text:"basic",value:"basic"},
        {text:"batch",value:"batch"},
        {text:"c",value:"c"},
        {text:"brainfuck",value:"brainfuck"},
        {text:"bro",value:"bro"},
        {text:"bison",value:"bison"},
        {text:"C#",value:"csharp"},
        {text:"C++",value:"cpp"},
        {text:"CoffeeScript",value:"coffeescript"},
        {text:"ruby",value:"ruby"},
        {text:"d",value:"d"},
        {text:"dart",value:"dart"},
        {text:"diff",value:"diff"},
        {text:"docker",value:"docker"},
        {text:"eiffel",value:"eiffel"},
        {text:"elixir",value:"elixir"},
        {text:"erlang",value:"erlang"},
        {text:"fsharp",value:"fsharp"},
        {text:"fortran",value:"fortran"},
        {text:"git",value:"git"},
        {text:"glsl",value:"glsl"},
        {text:"go",value:"go"},
        {text:"groovy",value:"groovy"},
        {text:"haml",value:"haml"},
        {text:"handlebars",value:"handlebars"},
        {text:"haskell",value:"haskell"},
        {text:"haxe",value:"haxe"},
        {text:"http",value:"http"},
        {text:"icon",value:"icon"},
        {text:"inform7",value:"inform7"},
        {text:"ini",value:"ini"},
        {text:"j",value:"j"},
        {text:"jade",value:"jade"},
        {text:"java",value:"java"},
        {text:"JSON",value:"json"},
        {text:"jsonp",value:"jsonp"},
        {text:"julia",value:"julia"},
        {text:"keyman",value:"keyman"},
        {text:"kotlin",value:"kotlin"},
        {text:"latex",value:"latex"},
        {text:"less",value:"less"},
        {text:"lolcode",value:"lolcode"},
        {text:"lua",value:"lua"},
        {text:"makefile",value:"makefile"},
        {text:"markdown",value:"markdown"},
        {text:"matlab",value:"matlab"},
        {text:"mel",value:"mel"},
        {text:"mizar",value:"mizar"},
        {text:"monkey",value:"monkey"},
        {text:"nasm",value:"nasm"},
        {text:"nginx",value:"nginx"},
        {text:"nim",value:"nim"},
        {text:"nix",value:"nix"},
        {text:"nsis",value:"nsis"},
        {text:"objectivec",value:"objectivec"},
        {text:"ocaml",value:"ocaml"},
        {text:"oz",value:"oz"},
        {text:"parigp",value:"parigp"},
        {text:"parser",value:"parser"},
        {text:"pascal",value:"pascal"},
        {text:"perl",value:"perl"},
        {text:"PHP",value:"php"},
        {text:"processing",value:"processing"},
        {text:"prolog",value:"prolog"},
        {text:"protobuf",value:"protobuf"},
        {text:"puppet",value:"puppet"},
        {text:"pure",value:"pure"},
        {text:"python",value:"python"},
        {text:"q",value:"q"},
        {text:"qore",value:"qore"},
        {text:"r",value:"r"},
        {text:"jsx",value:"jsx"},
        {text:"rest",value:"rest"},
        {text:"rip",value:"rip"},
        {text:"roboconf",value:"roboconf"},
        {text:"crystal",value:"crystal"},
        {text:"rust",value:"rust"},
        {text:"sas",value:"sas"},
        {text:"sass",value:"sass"},
        {text:"scss",value:"scss"},
        {text:"scala",value:"scala"},
        {text:"scheme",value:"scheme"},
        {text:"smalltalk",value:"smalltalk"},
        {text:"smarty",value:"smarty"},
        {text:"SQL",value:"sql"},
        {text:"stylus",value:"stylus"},
        {text:"swift",value:"swift"},
        {text:"tcl",value:"tcl"},
        {text:"textile",value:"textile"},
        {text:"twig",value:"twig"},
        {text:"TypeScript",value:"typescript"},
        {text:"verilog",value:"verilog"},
        {text:"vhdl",value:"vhdl"},
        {text:"wiki",value:"wiki"},
        {text:"YAML",value:"yaml"}
    ]
});

Happy coding !

Become a more social person