CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-prismjs

Lightweight, robust, elegant syntax highlighting library with support for 280+ languages and multiple themes

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

The plugin system provides extensible architecture for adding features and functionality to PrismJS. Plugins integrate with the highlighting process through hooks and extend capabilities with additional UI elements, processing logic, and specialized highlighting features.

Capabilities

Plugin Namespace

The main container for all loaded plugins and plugin-related functionality.

/**
 * Object containing all loaded plugins
 * @type {Object<string, Object>}
 */
Prism.plugins;

Usage Examples:

// Check if plugin is loaded
if (Prism.plugins.lineNumbers) {
    console.log('Line Numbers plugin is available');
}

// Access plugin functionality
Prism.plugins.fileHighlight.highlight(document);

// List all loaded plugins
console.log(Object.keys(Prism.plugins));
// Output: ['toolbar', 'lineNumbers', 'copyToClipboard', ...]

Hook System

Event-driven system allowing plugins to integrate with the highlighting process.

/**
 * Hook system for plugin integration and event handling
 */
Prism.hooks;

/**
 * Add callback function for specific hook event
 * @param {string} name - Hook name (before-highlight, after-highlight, etc.)
 * @param {function} callback - Function to execute when hook fires
 */
Prism.hooks.add(name, callback);

/**
 * Execute all callbacks registered for specific hook
 * @param {string} name - Hook name to execute
 * @param {object} env - Environment object passed to all callbacks
 */
Prism.hooks.run(name, env);

Available Hooks:

// Core highlighting hooks
'before-highlightall'      // Before highlighting all elements
'before-all-elements-highlight' // Before processing element list
'before-sanity-check'      // Before element validation
'before-highlight'         // Before highlighting single element
'before-insert'           // Before inserting highlighted HTML
'after-highlight'         // After highlighting complete
'complete'                // After DOM insertion complete
'wrap'                    // When wrapping tokens in HTML

// Token processing hooks
'before-tokenize'         // Before tokenization starts
'after-tokenize'          // After tokenization complete

Usage Examples:

// Add custom processing before highlighting
Prism.hooks.add('before-highlight', function(env) {
    // env.element, env.language, env.grammar, env.code
    console.log('About to highlight:', env.language);
    
    // Modify code before highlighting
    env.code = env.code.trim();
});

// Process tokens after tokenization
Prism.hooks.add('after-tokenize', function(env) {
    // env.tokens, env.code, env.grammar, env.language
    env.tokens.forEach(token => {
        if (token instanceof Prism.Token && token.type === 'comment') {
            token.alias = 'faded';
        }
    });
});

// Customize HTML wrapping for tokens
Prism.hooks.add('wrap', function(env) {
    // env.type, env.content, env.tag, env.attributes, env.language
    if (env.type === 'keyword') {
        env.attributes.title = `Keyword: ${env.content}`;
        env.attributes['data-tooltip'] = 'This is a language keyword';
    }
});

// Add custom completion logic
Prism.hooks.add('complete', function(env) {
    // env.element, env.highlightedCode
    env.element.setAttribute('data-highlighted', 'true');
    console.log('Highlighting complete for:', env.element);
});

Built-in Plugins

Line Numbers Plugin

Adds line numbers to code blocks.

/**
 * Line Numbers plugin functionality
 */
Prism.plugins.lineNumbers;

/**
 * Get line element for specific line number
 * @param {Element} element - Pre element with line numbers
 * @param {number} number - Line number to retrieve
 * @returns {Element|undefined} Line element or undefined
 */
Prism.plugins.lineNumbers.getLine(element, number);

/**
 * Resize line numbers to match code height
 * @param {Element} element - Pre element to resize
 */
Prism.plugins.lineNumbers.resize(element);

Usage Examples:

// Enable line numbers via CSS class
// <pre class="line-numbers"><code class="language-js">...</code></pre>

// Programmatically enable line numbers
const codeBlock = document.querySelector('pre');
codeBlock.classList.add('line-numbers');
Prism.highlightElement(codeBlock.querySelector('code'));

// Access specific line
const lineElement = Prism.plugins.lineNumbers.getLine(codeBlock, 5);
if (lineElement) {
    lineElement.style.backgroundColor = 'yellow';
}

// Resize after dynamic content changes
Prism.plugins.lineNumbers.resize(codeBlock);

Toolbar Plugin

Adds customizable toolbar to code blocks.

/**
 * Toolbar plugin functionality
 */
Prism.plugins.toolbar;

/**
 * Register new toolbar button
 * @param {string} key - Unique button identifier
 * @param {Object|function} button - Button configuration or factory function
 */
Prism.plugins.toolbar.registerButton(key, button);

/**
 * Get toolbar for specific code element
 * @param {Element} element - Code element
 * @returns {Element} Toolbar element
 */
Prism.plugins.toolbar.getToolbarElement(element);

Usage Examples:

// Register custom toolbar button
Prism.plugins.toolbar.registerButton('select-code', {
    text: 'Select All',
    onClick: function(env) {
        // env.element contains the code element
        const range = document.createRange();
        range.selectNodeContents(env.element);
        window.getSelection().removeAllRanges();
        window.getSelection().addRange(range);
    }
});

// Register button with dynamic content
Prism.plugins.toolbar.registerButton('show-language', function(env) {
    return {
        text: env.language.toUpperCase(),
        className: 'language-label',
    };
});

// Access toolbar after highlighting
Prism.hooks.add('complete', function(env) {
    const toolbar = Prism.plugins.toolbar.getToolbarElement(env.element);
    if (toolbar) {
        toolbar.style.backgroundColor = '#f0f0f0';
    }
});

Copy to Clipboard Plugin

Adds copy functionality to code blocks.

/**
 * Copy to Clipboard plugin (extends toolbar)
 */
Prism.plugins.copyToClipboard;

Usage Examples:

// Automatically adds copy button to toolbar
// No additional API - works automatically with toolbar plugin

// Customize copy button text
Prism.hooks.add('before-highlightall', function() {
    // This runs before the plugin initializes
    if (typeof Prism.plugins.toolbar !== 'undefined') {
        // Plugin will automatically register copy button
    }
});

// Listen for copy events
document.addEventListener('prism-copy-success', function(e) {
    console.log('Code copied:', e.detail.code);
});

document.addEventListener('prism-copy-error', function(e) {
    console.error('Copy failed:', e.detail.error);
});

File Highlight Plugin

Load and highlight external code files.

/**
 * File Highlight plugin functionality
 */
Prism.plugins.fileHighlight;

/**
 * Highlight external files in pre elements with data-src
 * @param {Element} [container=document] - Container to search within
 */
Prism.plugins.fileHighlight.highlight(container);

/**
 * @deprecated Use Prism.plugins.fileHighlight.highlight instead
 * Legacy function for backwards compatibility
 * @param {Element} [container=document] - Container to search within
 */
Prism.fileHighlight(container);

Usage Examples:

<!-- HTML setup for file highlighting -->
<pre data-src="example.js"></pre>
<pre data-src="styles.css" data-range="1,10"></pre>
<pre data-src="config.json" class="language-json"></pre>
// Manual file highlighting
Prism.plugins.fileHighlight.highlight(document);

// Highlight files in specific container
const container = document.getElementById('code-examples');
Prism.plugins.fileHighlight.highlight(container);

// Files are loaded asynchronously
Prism.hooks.add('complete', function(env) {
    if (env.element.hasAttribute('data-src')) {
        console.log('External file highlighted:', env.element.getAttribute('data-src'));
    }
});

Autoloader Plugin

Automatically load language definitions when needed.

/**
 * Autoloader plugin functionality
 */
Prism.plugins.autoloader;

/**
 * Set path template for loading language files
 * @param {string} template - Path template with {id} placeholder
 */
Prism.plugins.autoloader.languages_path;

/**
 * Load specific languages
 * @param {string|string[]} languages - Language IDs to load
 * @param {function} [success] - Success callback
 * @param {function} [error] - Error callback
 */
Prism.plugins.autoloader.loadLanguages(languages, success, error);

Usage Examples:

// Configure autoloader path
Prism.plugins.autoloader.languages_path = 'components/prism-{id}.min.js';

// Languages are loaded automatically when encountered
// <pre><code class="language-python">print("Hello")</code></pre>
// Python grammar will be loaded automatically

// Manual language loading
Prism.plugins.autoloader.loadLanguages(['python', 'rust'], function() {
    console.log('Languages loaded successfully');
    // Now highlight code
    Prism.highlightAll();
}, function() {
    console.error('Failed to load languages');
});

// Load single language
Prism.plugins.autoloader.loadLanguages('go');

Additional Plugins

/**
 * Line Highlight - Highlight specific lines
 */
Prism.plugins.lineHighlight;

/**
 * Match Braces - Highlight matching brackets
 */
Prism.plugins.matchBraces;

/**
 * Show Invisibles - Display whitespace characters
 */
Prism.plugins.showInvisibles;

/**
 * Normalize Whitespace - Clean up code formatting
 */
Prism.plugins.normalizeWhitespace;

/**
 * Command Line - Style command-line sessions
 */
Prism.plugins.commandLine;

/**
 * Diff Highlight - Highlight code differences
 */
Prism.plugins.diffHighlight;

Plugin Development

Creating Custom Plugins

// Basic plugin structure
(function() {
    if (typeof Prism === 'undefined' || typeof document === 'undefined') {
        return;
    }
    
    // Plugin configuration
    var config = Prism.plugins.myPlugin = {
        setting1: 'default value',
        setting2: true
    };
    
    // Plugin functionality
    function doSomething(element) {
        // Plugin logic
        element.classList.add('my-plugin-processed');
    }
    
    // Hook into highlighting process
    Prism.hooks.add('complete', function(env) {
        if (env.element.classList.contains('my-plugin-enabled')) {
            doSomething(env.element);
        }
    });
})();

Plugin Best Practices

// Environment detection
if (typeof Prism === 'undefined' || typeof document === 'undefined') {
    return; // Exit if not in browser with Prism
}

// Feature detection
if (!document.querySelector) {
    return; // Exit if required DOM methods unavailable
}

// Plugin namespace
var MyPlugin = Prism.plugins.myPlugin = {
    // Public API
    process: function(element) {
        // Implementation
    },
    
    // Configuration
    config: {
        option1: true,
        option2: 'default'
    }
};

// Safe hook registration
Prism.hooks.add('complete', function(env) {
    try {
        MyPlugin.process(env.element);
    } catch (error) {
        console.error('MyPlugin error:', error);
    }
});

Plugin Integration Patterns

// Toolbar integration
if (Prism.plugins.toolbar) {
    Prism.plugins.toolbar.registerButton('my-button', {
        text: 'My Action',
        onClick: function(env) {
            // Button click handler
            console.log('Button clicked for:', env.language);
        }
    });
}

// CSS class detection
Prism.hooks.add('before-sanity-check', function(env) {
    if (env.element.classList.contains('my-plugin')) {
        // Plugin-specific processing
        env.element.setAttribute('data-processed', 'my-plugin');
    }
});

// Language-specific plugins
Prism.hooks.add('after-tokenize', function(env) {
    if (env.language === 'javascript') {
        // JavaScript-specific token processing
        processJavaScriptTokens(env.tokens);
    }
});

Plugin Loading and Dependencies

// Check plugin dependencies
function hasRequiredPlugins() {
    return Prism.plugins.toolbar && Prism.plugins.lineNumbers;
}

if (hasRequiredPlugins()) {
    // Initialize plugin that depends on others
    initializeComplexPlugin();
} else {
    console.warn('Required plugins not loaded');
}

// Dynamic plugin loading
function loadPlugin(pluginPath, callback) {
    const script = document.createElement('script');
    script.src = pluginPath;
    script.onload = callback;
    script.onerror = function() {
        console.error('Failed to load plugin:', pluginPath);
    };
    document.head.appendChild(script);
}

// Load plugin chain
loadPlugin('plugins/toolbar/prism-toolbar.js', function() {
    loadPlugin('plugins/copy-to-clipboard/prism-copy-to-clipboard.js', function() {
        console.log('All plugins loaded');
        Prism.highlightAll();
    });
});

Install with Tessl CLI

npx tessl i tessl/npm-prismjs

docs

core-highlighting.md

index.md

language-system.md

plugin-system.md

token-system.md

utilities.md

tile.json