Theme Customization for Highlight.js & Prism.js | Web Formatter Blog

Theme Customization for Highlight.js & Prism.js
A comprehensive guide to creating beautiful custom themes for popular syntax highlighters.
Introduction to Syntax Highlighter Themes
Syntax highlighting is essential for making code readable and understandable on websites, documentation, and blogs. While Highlight.js and Prism.js come with several built-in themes, creating custom themes allows you to match your brand identity and provide a unique experience for your users.
This guide will walk you through the process of creating custom themes for both Highlight.js and Prism.js, two of the most popular syntax highlighting libraries. We'll cover everything from understanding the basic structure of themes to implementing responsive and accessible designs.
Highlight.js Overview
Highlight.js is a syntax highlighter written in JavaScript that works in browsers and on the server. It automatically detects the language of code blocks and applies appropriate highlighting.
Key features of Highlight.js include:
- Support for 189+ languages and 94+ styles
- Automatic language detection
- Multi-language code highlighting
- Compatible with any markup
- Works with any JS framework
function greet(name) {
return `Hello, \${name}!`;
}
console.log(greet('World'));
Prism.js Overview
Prism.js is a lightweight, extensible syntax highlighter built with modern web standards in mind. It's used by thousands of websites including some notable ones like MDN, WordPress, and Deno.
Key features of Prism.js include:
- Support for over 200 languages
- Multiple themes available
- Plugin architecture for extended functionality
- Line highlighting and line numbers
- Small footprint (~2KB minified and gzipped)
function greet(name) {
return `Hello, \${name}!`;
}
console.log(greet('World'));
Theme Basics
Before diving into creating custom themes, it's important to understand some basic concepts that apply to both libraries.
Using CSS Variables
Modern themes often use CSS variables (custom properties) to maintain consistency and make themes easier to customize:
:root {
--code-bg: #282c34;
--code-text: #abb2bf;
--code-keyword: #c678dd;
--code-function: #61afef;
--code-string: #98c379;
--code-number: #d19a66;
--code-comment: #5c6370;
}
code {
background-color: var(--code-bg);
color: var(--code-text);
}
.token.keyword {
color: var(--code-keyword);
}
Understanding Token Types
Both Highlight.js and Prism.js break down code into "tokens" - small pieces of code that share the same syntax role. Common token types include:
-
keyword: Programming language keywords like{" "}
if
,function
,return
- string: String literals
- number: Numeric literals
- comment: Code comments
- function: Function names
-
operator: Operators like
+
,{" "}-
,=
-
punctuation: Punctuation marks like{" "}
;
,,
,.
Each library has its own specific token classes, which we'll explore in detail.
Creating Custom Highlight.js Themes
Creating a custom theme for Highlight.js involves writing CSS that targets the specific classes it generates.
Theme Structure
A basic Highlight.js theme structure looks like this:
/* Base style for code blocks */
.hljs {
display: block;
overflow-x: auto;
padding: 1em;
background: #282c34;
color: #abb2bf;
}
/* Comments */
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
/* Keywords */
.hljs-keyword,
.hljs-selector-tag {
color: #c678dd;
}
/* And so on for other token types */
Styling Tokens
Here's a more comprehensive list of Highlight.js token classes and what they represent:
/* Strings */
.hljs-string,
.hljs-doctag,
.hljs-regexp {
color: #98c379;
}
/* Numbers */
.hljs-number,
.hljs-literal {
color: #d19a66;
}
/* Functions */
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #61afef;
}
/* Variables */
.hljs-variable,
.hljs-template-variable {
color: #e06c75;
}
/* Built-in types and constants */
.hljs-type,
.hljs-built_in,
.hljs-builtin-name,
.hljs-symbol,
.hljs-selector-class {
color: #e5c07b;
}
/* Attributes */
.hljs-attr,
.hljs-attribute,
.hljs-selector-attr {
color: #d19a66;
}
/* Meta information */
.hljs-meta,
.hljs-meta-keyword,
.hljs-meta-string {
color: #56b6c2;
}
/* Tags */
.hljs-name,
.hljs-tag {
color: #e06c75;
}
/* Emphasis */
.hljs-emphasis {
font-style: italic;
}
/* Strong */
.hljs-strong {
font-weight: bold;
}
Complete Example
Let's create a complete custom theme for Highlight.js inspired by the popular "One Dark" color scheme:
/**
* One Dark inspired theme for Highlight.js
*/
.hljs {
display: block;
overflow-x: auto;
padding: 1em;
color: #abb2bf;
background: #282c34;
border-radius: 0.5em;
}
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula,
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #c678dd;
}
.hljs-literal,
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
color: #98c379;
}
.hljs-built_in,
.hljs-class .hljs-title,
.hljs-title.class_ {
color: #e5c07b;
}
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #d19a66;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title,
.hljs-title.function_ {
color: #61afef;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}
To use this theme, save it as a CSS file (e.g.,{" "}
one-dark.css
) and include it in your HTML instead of
the default theme:
Creating Custom Prism.js Themes
Prism.js uses a different class naming convention but follows similar principles for theming.
Theme Structure
A basic Prism.js theme structure looks like this:
/**
* Custom theme for Prism.js
*/
code[class*="language-"],
pre[class*="language-"] {
color: #abb2bf;
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
tab-size: 4;
hyphens: none;
}
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
background: #282c34;
}
/* Token styles go here */
Styling Tokens
Prism.js uses the .token
prefix for all its syntax
elements. Here's a comprehensive list of token classes:
/* Comments */
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #5c6370;
font-style: italic;
}
/* Punctuation */
.token.punctuation {
color: #abb2bf;
}
/* Namespaces */
.token.namespace {
opacity: .7;
}
/* Properties, tags, and boolean */
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #e06c75;
}
/* Selectors, attributes, and strings */
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #98c379;
}
/* Operators and entities */
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #56b6c2;
}
/* Keywords, variables, and regex */
.token.atrule,
.token.attr-value,
.token.keyword {
color: #c678dd;
}
/* Functions */
.token.function,
.token.class-name {
color: #61afef;
}
/* Regex and important */
.token.regex,
.token.important {
color: #d19a66;
}
/* Important and bold */
.token.important,
.token.bold {
font-weight: bold;
}
/* Italic */
.token.italic {
font-style: italic;
}
Complete Example
Let's create a complete custom theme for Prism.js inspired by the "One Dark" color scheme:
/**
* One Dark theme for Prism.js
*/
code[class*="language-"],
pre[class*="language-"] {
color: #abb2bf;
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
tab-size: 4;
hyphens: none;
}
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
background: #282c34;
}
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
background: #282c34;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #5c6370;
font-style: italic;
}
.token.punctuation {
color: #abb2bf;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #e06c75;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #98c379;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #56b6c2;
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #c678dd;
}
.token.function,
.token.class-name {
color: #61afef;
}
.token.regex,
.token.important,
.token.variable {
color: #d19a66;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
To use this theme, save it as a CSS file (e.g.,{" "}
prism-one-dark.css
) and include it in your HTML
instead of the default theme:
Dark and Light Theme Variants
Many websites now offer both dark and light modes. Creating theme variants for both modes ensures a good user experience regardless of preference.
Here's how to structure your CSS to support both dark and light themes:
/* Light theme (default) */
:root {
--code-bg: #f5f5f5;
--code-text: #383a42;
--code-keyword: #a626a4;
--code-function: #4078f2;
--code-string: #50a14f;
--code-number: #986801;
--code-comment: #a0a1a7;
}
/* Dark theme */
[data-theme="dark"] {
--code-bg: #282c34;
--code-text: #abb2bf;
--code-keyword: #c678dd;
--code-function: #61afef;
--code-string: #98c379;
--code-number: #d19a66;
--code-comment: #5c6370;
}
/* Highlight.js theme using variables */
.hljs {
background: var(--code-bg);
color: var(--code-text);
}
.hljs-keyword {
color: var(--code-keyword);
}
/* And so on for other tokens */
This approach uses CSS variables and a data-theme
{" "}
attribute on the root element to switch between themes.
Implementing Theme Switching
To allow users to switch between themes, you'll need some JavaScript:
// Theme switcher function
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
// Set the theme attribute
document.documentElement.setAttribute('data-theme', newTheme);
// Store preference in localStorage
localStorage.setItem('theme', newTheme);
}
// Initialize theme based on user preference
function initTheme() {
// Check for saved theme preference or prefer-color-scheme
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
// Set initial theme
if (savedTheme) {
document.documentElement.setAttribute('data-theme', savedTheme);
} else if (prefersDark) {
document.documentElement.setAttribute('data-theme', 'dark');
}
}
// Call initTheme when the page loads
document.addEventListener('DOMContentLoaded', initTheme);
// Example: Add event listener to a theme toggle button
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);
This script checks for user preferences in localStorage and
respects the system preference via{" "}
prefers-color-scheme
media query.
Responsive Theme Considerations
When designing syntax highlighting themes, consider how they'll appear on different screen sizes:
- Adjust font sizes for better readability on mobile devices
- Consider horizontal scrolling for code blocks on small screens
- Ensure padding and margins work well across devices
/* Base styles */
.hljs {
font-size: 14px;
padding: 1em;
border-radius: 0.5em;
overflow-x: auto;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.hljs {
font-size: 13px;
padding: 0.75em;
border-radius: 0.3em;
}
}
@media (max-width: 480px) {
.hljs {
font-size: 12px;
padding: 0.5em;
line-height: 1.4;
}
}
Accessibility Considerations
Accessibility should be a priority when designing syntax highlighting themes. Here are some key considerations:
Color Contrast Ratios
Ensure that your theme colors have sufficient contrast ratios to meet WCAG guidelines:
- Text should have a contrast ratio of at least 4.5:1 against its background
- Large text (18pt or 14pt bold) should have a contrast ratio of at least 3:1
- Use tools like the WebAIM Contrast Checker to verify your color choices
For example, light gray text (#abb2bf) on a dark background (#282c34) has a contrast ratio of about 6.7:1, which meets WCAG AA standards.
Focus States
If your code blocks are interactive (e.g., clickable to copy), ensure they have visible focus states:
pre:focus, code:focus {
outline: 2px solid #61afef;
outline-offset: 2px;
}
Distributing Your Themes
Once you've created your custom themes, you might want to share them with others.
NPM Packages
For JavaScript projects, publishing your theme as an NPM package makes it easy to install and use:
# Create a package.json file
npm init
# Add your theme files
# - src/
# - highlight-theme.css
# - prism-theme.css
# Publish to NPM
npm publish
Users can then install your theme with:
npm install your-theme-package
CDN Distribution
For broader accessibility, consider hosting your theme on a CDN like jsDelivr or CDNJS:
- Publish your theme to GitHub
- Use jsDelivr to serve directly from your repository
Best Practices
Follow these best practices when creating custom syntax highlighting themes:
- Consistency: Use consistent colors for the same token types across languages
- Readability: Prioritize readability over aesthetics
- Accessibility: Ensure sufficient color contrast for all users
- Documentation: Document your theme's color scheme and token mappings
- Testing: Test your theme with multiple languages and code examples
- Versioning: Use semantic versioning if distributing your theme
- Fallbacks: Provide fallbacks for browsers that don't support CSS variables
Conclusion
Creating custom themes for syntax highlighters like Highlight.js and Prism.js allows you to provide a consistent, branded experience that matches your website's design. By understanding token types, using CSS variables, and following accessibility best practices, you can create beautiful, functional themes that enhance code readability.
Whether you're creating themes for personal projects or distributing them to the community, the techniques covered in this guide will help you build professional, responsive, and accessible syntax highlighting themes.