Advanced Markdown Code Syntax Highlighting: Complete Guide for Multi-Language Support, Custom Themes, and Interactive Documentation
Advanced Markdown code syntax highlighting transforms static code examples into visually rich, interactive documentation that enhances readability, comprehension, and user engagement across technical content. By implementing sophisticated syntax highlighting systems, custom theme integration, and intelligent language detection, technical writers can create comprehensive documentation that effectively communicates complex programming concepts while maintaining consistency across diverse codebases and programming languages.
Why Implement Advanced Syntax Highlighting?
Professional syntax highlighting provides essential benefits for technical documentation:
- Code Readability: Enhanced visual distinction between syntax elements improves code comprehension
- Language Support: Comprehensive highlighting for 200+ programming languages and markup formats
- Theme Customization: Brand-consistent highlighting that matches documentation design systems
- Interactive Features: Copy buttons, line numbers, and collapsible sections enhance user experience
- Accessibility: High-contrast themes and screen reader compatibility ensure inclusive documentation
- Performance: Optimized rendering engines handle large code blocks without impacting page load times
Foundation Syntax Highlighting Systems
Prism.js Advanced Implementation
Setting up comprehensive syntax highlighting with Prism.js and modern extensions:
// prism-advanced-setup.js - Advanced Prism.js configuration
class AdvancedPrismHighlighter {
constructor(options = {}) {
this.options = {
theme: 'default',
languages: ['javascript', 'python', 'java', 'cpp', 'bash'],
enableLineNumbers: true,
enableCopyButton: true,
enableLanguageLabels: true,
enableCodeFolding: false,
enableInlineColors: true,
enableDiffHighlighting: true,
autoDetectLanguage: true,
tabSize: 4,
maxHeight: '500px',
...options
};
this.loadedLanguages = new Set();
this.languageAliases = new Map([
['js', 'javascript'],
['ts', 'typescript'],
['py', 'python'],
['sh', 'bash'],
['yml', 'yaml'],
['md', 'markdown']
]);
this.init();
}
async init() {
await this.loadPrismCore();
await this.loadTheme();
await this.loadLanguages();
await this.loadPlugins();
this.setupCodeBlocks();
this.bindEvents();
}
async loadPrismCore() {
if (typeof Prism === 'undefined') {
await this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js');
}
}
async loadTheme() {
const themeUrl = this.getThemeUrl(this.options.theme);
await this.loadCSS(themeUrl);
}
getThemeUrl(theme) {
const themes = {
'default': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css',
'dark': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-dark.min.css',
'okaidia': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css',
'tomorrow': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css',
'twilight': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-twilight.min.css',
'coy': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-coy.min.css',
'funky': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-funky.min.css',
'solarizedlight': 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-solarizedlight.min.css'
};
return themes[theme] || themes['default'];
}
async loadLanguages() {
const baseUrl = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/';
for (const language of this.options.languages) {
const normalizedLang = this.languageAliases.get(language) || language;
if (!this.loadedLanguages.has(normalizedLang) && normalizedLang !== 'markup') {
try {
await this.loadScript(`${baseUrl}prism-${normalizedLang}.min.js`);
this.loadedLanguages.add(normalizedLang);
} catch (error) {
console.warn(`Failed to load language: ${normalizedLang}`, error);
}
}
}
// Load common dependencies
await this.loadLanguageDependencies();
}
async loadLanguageDependencies() {
const dependencies = {
'typescript': ['javascript'],
'jsx': ['javascript'],
'tsx': ['jsx', 'typescript'],
'scss': ['css'],
'less': ['css'],
'stylus': ['css'],
'php': ['markup'],
'smarty': ['markup'],
'django': ['markup'],
'handlebars': ['markup'],
'erb': ['ruby', 'markup']
};
for (const [lang, deps] of Object.entries(dependencies)) {
if (this.options.languages.includes(lang)) {
for (const dep of deps) {
if (!this.loadedLanguages.has(dep)) {
await this.loadLanguage(dep);
}
}
}
}
}
async loadLanguage(language) {
if (this.loadedLanguages.has(language)) return;
const baseUrl = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/';
try {
await this.loadScript(`${baseUrl}prism-${language}.min.js`);
this.loadedLanguages.add(language);
} catch (error) {
console.warn(`Failed to load language dependency: ${language}`, error);
}
}
async loadPlugins() {
const plugins = [];
if (this.options.enableLineNumbers) {
plugins.push(this.loadLineNumbers());
}
if (this.options.enableCopyButton) {
plugins.push(this.loadCopyButton());
}
if (this.options.enableCodeFolding) {
plugins.push(this.loadCodeFolding());
}
if (this.options.enableDiffHighlighting) {
plugins.push(this.loadDiffHighlighting());
}
await Promise.all(plugins);
}
async loadLineNumbers() {
await this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js');
await this.loadCSS('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css');
}
async loadCopyButton() {
await this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js');
}
async loadCodeFolding() {
// Custom implementation for code folding
this.setupCodeFolding();
}
async loadDiffHighlighting() {
await this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/diff-highlight/prism-diff-highlight.min.js');
await this.loadCSS('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/diff-highlight/prism-diff-highlight.min.css');
}
setupCodeBlocks() {
const codeBlocks = document.querySelectorAll('pre[class*="language-"], code[class*="language-"]');
codeBlocks.forEach(block => {
this.enhanceCodeBlock(block);
});
// Auto-detect language for unmarked code blocks
if (this.options.autoDetectLanguage) {
this.autoDetectLanguages();
}
}
enhanceCodeBlock(block) {
const pre = block.tagName === 'PRE' ? block : block.closest('pre');
if (!pre) return;
// Add wrapper div for enhanced styling
if (!pre.closest('.code-block-wrapper')) {
const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
this.addLanguageLabel(wrapper, pre);
this.addCodeToolbar(wrapper, pre);
this.setupCodeInteractions(wrapper, pre);
}
// Add line numbers if enabled
if (this.options.enableLineNumbers && !pre.classList.contains('line-numbers')) {
pre.classList.add('line-numbers');
}
// Set max height if specified
if (this.options.maxHeight) {
pre.style.maxHeight = this.options.maxHeight;
pre.style.overflow = 'auto';
}
// Apply tab size
if (this.options.tabSize) {
pre.style.tabSize = this.options.tabSize;
}
}
addLanguageLabel(wrapper, pre) {
if (!this.options.enableLanguageLabels) return;
const className = pre.className;
const langMatch = className.match(/language-([a-zA-Z0-9-]+)/);
if (langMatch) {
const language = langMatch[1];
const label = document.createElement('div');
label.className = 'language-label';
label.textContent = this.formatLanguageName(language);
label.setAttribute('aria-label', `Code language: ${language}`);
wrapper.appendChild(label);
}
}
formatLanguageName(language) {
const names = {
'js': 'JavaScript',
'ts': 'TypeScript',
'py': 'Python',
'cpp': 'C++',
'cs': 'C#',
'rb': 'Ruby',
'go': 'Go',
'rs': 'Rust',
'php': 'PHP',
'java': 'Java',
'kt': 'Kotlin',
'swift': 'Swift',
'dart': 'Dart',
'scala': 'Scala',
'clj': 'Clojure',
'hs': 'Haskell',
'ml': 'ML',
'fs': 'F#',
'sh': 'Shell',
'bash': 'Bash',
'zsh': 'Zsh',
'ps1': 'PowerShell',
'sql': 'SQL',
'html': 'HTML',
'xml': 'XML',
'css': 'CSS',
'scss': 'SCSS',
'sass': 'Sass',
'less': 'Less',
'stylus': 'Stylus',
'json': 'JSON',
'yaml': 'YAML',
'toml': 'TOML',
'ini': 'INI',
'md': 'Markdown',
'tex': 'LaTeX',
'dockerfile': 'Dockerfile',
'nginx': 'Nginx',
'apache': 'Apache'
};
return names[language] || language.toUpperCase();
}
addCodeToolbar(wrapper, pre) {
const toolbar = document.createElement('div');
toolbar.className = 'code-toolbar';
// Copy button
if (this.options.enableCopyButton) {
const copyButton = document.createElement('button');
copyButton.className = 'copy-button';
copyButton.textContent = 'Copy';
copyButton.setAttribute('aria-label', 'Copy code to clipboard');
copyButton.addEventListener('click', () => this.copyCode(pre, copyButton));
toolbar.appendChild(copyButton);
}
// Expand/collapse button
if (this.options.enableCodeFolding) {
const foldButton = document.createElement('button');
foldButton.className = 'fold-button';
foldButton.textContent = 'Collapse';
foldButton.setAttribute('aria-label', 'Toggle code visibility');
foldButton.addEventListener('click', () => this.toggleCodeFold(pre, foldButton));
toolbar.appendChild(foldButton);
}
// Download button
const downloadButton = document.createElement('button');
downloadButton.className = 'download-button';
downloadButton.textContent = 'Download';
downloadButton.setAttribute('aria-label', 'Download code as file');
downloadButton.addEventListener('click', () => this.downloadCode(pre));
toolbar.appendChild(downloadButton);
wrapper.appendChild(toolbar);
}
setupCodeInteractions(wrapper, pre) {
// Add focus management for keyboard navigation
pre.setAttribute('tabindex', '0');
pre.setAttribute('role', 'textbox');
pre.setAttribute('aria-label', 'Code example');
pre.setAttribute('aria-readonly', 'true');
// Add keyboard shortcuts
pre.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case 'c':
e.preventDefault();
this.copyCode(pre);
break;
case 'a':
e.preventDefault();
this.selectAllCode(pre);
break;
}
}
});
// Add double-click to select all
pre.addEventListener('dblclick', () => {
this.selectAllCode(pre);
});
}
copyCode(pre, button = null) {
const code = pre.querySelector('code');
const text = code ? code.textContent : pre.textContent;
navigator.clipboard.writeText(text).then(() => {
this.showCopyFeedback(button || pre);
}).catch(err => {
console.error('Failed to copy code:', err);
// Fallback for older browsers
this.fallbackCopy(text);
});
}
showCopyFeedback(element) {
const originalText = element.textContent;
element.textContent = 'Copied!';
element.classList.add('copied');
setTimeout(() => {
element.textContent = originalText;
element.classList.remove('copied');
}, 2000);
}
fallbackCopy(text) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
this.showGlobalCopyFeedback();
} catch (err) {
console.error('Fallback copy failed:', err);
}
document.body.removeChild(textArea);
}
showGlobalCopyFeedback() {
const feedback = document.createElement('div');
feedback.className = 'copy-feedback';
feedback.textContent = 'Code copied to clipboard';
feedback.setAttribute('aria-live', 'polite');
document.body.appendChild(feedback);
setTimeout(() => {
feedback.classList.add('show');
}, 10);
setTimeout(() => {
feedback.classList.remove('show');
setTimeout(() => {
document.body.removeChild(feedback);
}, 300);
}, 2000);
}
selectAllCode(pre) {
const range = document.createRange();
range.selectNodeContents(pre);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
toggleCodeFold(pre, button) {
const isFolded = pre.classList.contains('folded');
if (isFolded) {
pre.classList.remove('folded');
button.textContent = 'Collapse';
button.setAttribute('aria-expanded', 'true');
} else {
pre.classList.add('folded');
button.textContent = 'Expand';
button.setAttribute('aria-expanded', 'false');
}
}
downloadCode(pre) {
const code = pre.querySelector('code');
const text = code ? code.textContent : pre.textContent;
const language = this.extractLanguage(pre);
const extension = this.getFileExtension(language);
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `code-example.${extension}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
extractLanguage(pre) {
const className = pre.className;
const match = className.match(/language-([a-zA-Z0-9-]+)/);
return match ? match[1] : 'txt';
}
getFileExtension(language) {
const extensions = {
'javascript': 'js',
'typescript': 'ts',
'python': 'py',
'java': 'java',
'cpp': 'cpp',
'c': 'c',
'csharp': 'cs',
'ruby': 'rb',
'go': 'go',
'rust': 'rs',
'php': 'php',
'kotlin': 'kt',
'swift': 'swift',
'dart': 'dart',
'scala': 'scala',
'clojure': 'clj',
'haskell': 'hs',
'bash': 'sh',
'shell': 'sh',
'powershell': 'ps1',
'sql': 'sql',
'html': 'html',
'css': 'css',
'scss': 'scss',
'sass': 'sass',
'less': 'less',
'json': 'json',
'yaml': 'yaml',
'xml': 'xml',
'markdown': 'md',
'dockerfile': 'dockerfile'
};
return extensions[language] || 'txt';
}
autoDetectLanguages() {
const untaggedBlocks = document.querySelectorAll('pre:not([class*="language-"]) code, code:not([class*="language-"])');
untaggedBlocks.forEach(block => {
const text = block.textContent;
const detectedLanguage = this.detectLanguage(text);
if (detectedLanguage) {
block.className = `language-${detectedLanguage}`;
if (block.closest('pre')) {
block.closest('pre').className = `language-${detectedLanguage}`;
}
}
});
}
detectLanguage(code) {
// Simple heuristic-based language detection
const patterns = {
'javascript': [
/\b(function|const|let|var|=>|async|await|require|import)\b/,
/\bconsole\.log\b/,
/\b(document|window)\./,
/\$\(/
],
'python': [
/\b(def|class|import|from|if __name__|print|range|len)\b/,
/:\s*$/m,
/\bindent/
],
'java': [
/\b(public|private|protected|static|void|class|interface)\b/,
/\bSystem\.out\.print/,
/\bpublic static void main\b/
],
'html': [
/<\/?[a-zA-Z][^>]*>/,
/<!DOCTYPE/i,
/<html|<head|<body/i
],
'css': [
/\{[^}]*\}/,
/[a-zA-Z-]+\s*:\s*[^;]+;/,
/@media|@import|@keyframes/
],
'sql': [
/\b(SELECT|FROM|WHERE|JOIN|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i
],
'bash': [
/^#!/,
/\$[A-Za-z_][A-Za-z0-9_]*/,
/\becho|grep|awk|sed|ls|cd|mkdir\b/
]
};
for (const [language, regexes] of Object.entries(patterns)) {
if (regexes.some(regex => regex.test(code))) {
return language;
}
}
return null;
}
async loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
async loadCSS(href) {
return new Promise((resolve, reject) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
}
bindEvents() {
// Handle dynamically added code blocks
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
const codeBlocks = node.querySelectorAll('pre[class*="language-"], code[class*="language-"]');
codeBlocks.forEach(block => {
this.enhanceCodeBlock(block);
});
// Re-run Prism highlighting
if (typeof Prism !== 'undefined' && Prism.highlightAllUnder) {
Prism.highlightAllUnder(node);
}
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// Public API
highlightElement(element) {
if (typeof Prism !== 'undefined') {
Prism.highlightElement(element);
this.enhanceCodeBlock(element);
}
}
addLanguage(name, grammar) {
if (typeof Prism !== 'undefined') {
Prism.languages[name] = grammar;
this.loadedLanguages.add(name);
}
}
setTheme(theme) {
this.options.theme = theme;
this.loadTheme();
}
updateOptions(newOptions) {
this.options = { ...this.options, ...newOptions };
this.setupCodeBlocks();
}
}
// Enhanced CSS for advanced syntax highlighting
const advancedSyntaxStyles = `
/* Code block wrapper styling */
.code-block-wrapper {
position: relative;
margin: 1.5rem 0;
border-radius: 8px;
background: #f8f9fa;
border: 1px solid #e9ecef;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Language label */
.language-label {
position: absolute;
top: 8px;
right: 8px;
background: rgba(0,0,0,0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
z-index: 10;
pointer-events: none;
}
/* Code toolbar */
.code-toolbar {
position: absolute;
top: 8px;
right: 8px;
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.2s ease;
z-index: 10;
}
.code-block-wrapper:hover .code-toolbar {
opacity: 1;
}
.code-toolbar button {
background: rgba(0,0,0,0.7);
color: white;
border: none;
padding: 6px 10px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.code-toolbar button:hover {
background: rgba(0,0,0,0.9);
}
.code-toolbar button:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
.code-toolbar button.copied {
background: #28a745;
}
/* Enhanced pre styling */
.code-block-wrapper pre {
margin: 0;
padding: 16px;
background: inherit;
border-radius: 0;
font-size: 14px;
line-height: 1.5;
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Courier New', monospace;
overflow-x: auto;
tab-size: 4;
}
.code-block-wrapper pre:focus {
outline: 2px solid #007bff;
outline-offset: -2px;
}
/* Code folding */
.code-block-wrapper pre.folded {
max-height: 100px;
overflow: hidden;
position: relative;
}
.code-block-wrapper pre.folded::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: linear-gradient(transparent, #f8f9fa);
pointer-events: none;
}
/* Line numbers enhancement */
.line-numbers-rows {
padding-left: 0 !important;
border-right: 1px solid #e9ecef;
margin-right: 16px;
padding-right: 8px;
}
.line-numbers-rows > span:before {
color: #6c757d;
font-weight: normal;
}
/* Copy feedback */
.copy-feedback {
position: fixed;
top: 20px;
right: 20px;
background: #28a745;
color: white;
padding: 12px 20px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
transform: translateX(100%);
opacity: 0;
transition: all 0.3s ease;
z-index: 9999;
}
.copy-feedback.show {
transform: translateX(0);
opacity: 1;
}
/* Dark theme support */
@media (prefers-color-scheme: dark) {
.code-block-wrapper {
background: #1e1e1e;
border-color: #404040;
}
.line-numbers-rows {
border-right-color: #404040;
}
.line-numbers-rows > span:before {
color: #888;
}
}
/* High contrast mode */
@media (prefers-contrast: high) {
.code-block-wrapper {
border: 2px solid #000;
background: #fff;
}
.code-toolbar button {
background: #000;
color: #fff;
border: 1px solid #fff;
}
.language-label {
background: #000;
color: #fff;
border: 1px solid #fff;
}
}
/* Reduced motion preferences */
@media (prefers-reduced-motion: reduce) {
.code-toolbar,
.copy-feedback,
.code-toolbar button {
transition: none;
}
}
/* Mobile optimizations */
@media (max-width: 768px) {
.code-block-wrapper pre {
padding: 12px;
font-size: 13px;
}
.code-toolbar {
opacity: 1; /* Always show on mobile */
position: static;
background: rgba(0,0,0,0.05);
padding: 8px;
border-bottom: 1px solid #e9ecef;
justify-content: flex-end;
}
.language-label {
position: static;
background: rgba(0,0,0,0.05);
color: inherit;
padding: 8px 12px;
border-bottom: 1px solid #e9ecef;
border-radius: 0;
}
}
/* Print styles */
@media print {
.code-toolbar,
.language-label {
display: none;
}
.code-block-wrapper {
break-inside: avoid;
box-shadow: none;
border: 1px solid #000;
}
.code-block-wrapper pre {
white-space: pre-wrap;
word-wrap: break-word;
}
}
/* Accessibility improvements */
.code-block-wrapper pre[aria-label]:focus::before {
content: attr(aria-label);
position: absolute;
top: -30px;
left: 0;
background: #000;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
z-index: 1000;
}
/* Language-specific enhancements */
.language-diff .token.inserted {
background: rgba(40, 167, 69, 0.2);
color: #155724;
}
.language-diff .token.deleted {
background: rgba(220, 53, 69, 0.2);
color: #721c24;
}
.token.comment {
font-style: italic;
}
.token.string,
.token.attr-value {
quotes: '"' '"';
}
.token.url {
text-decoration: underline;
}
/* Custom tokens for enhanced highlighting */
.token.this,
.token.super {
color: #e83e8c;
}
.token.console {
color: #6f42c1;
}
.token.dom {
color: #fd7e14;
}
.token.filesystem {
color: #20c997;
}
`;
// Inject enhanced styles
if (typeof document !== 'undefined') {
const style = document.createElement('style');
style.textContent = advancedSyntaxStyles;
document.head.appendChild(style);
}
// Initialize advanced syntax highlighting
document.addEventListener('DOMContentLoaded', function() {
new AdvancedPrismHighlighter({
theme: 'default',
languages: [
'javascript', 'typescript', 'python', 'java', 'cpp', 'c', 'csharp',
'ruby', 'go', 'rust', 'php', 'kotlin', 'swift', 'dart', 'scala',
'bash', 'powershell', 'sql', 'html', 'css', 'scss', 'json', 'yaml',
'markdown', 'dockerfile', 'nginx', 'apache'
],
enableLineNumbers: true,
enableCopyButton: true,
enableLanguageLabels: true,
enableCodeFolding: false,
autoDetectLanguage: true,
maxHeight: '600px'
});
});
// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
module.exports = AdvancedPrismHighlighter;
}
if (typeof define === 'function' && define.amd) {
define([], function() {
return AdvancedPrismHighlighter;
});
}
Custom Theme Development
Creating brand-consistent syntax highlighting themes:
# Custom Theme Creation System
## CSS-in-JS Theme Builder
```javascript
// theme-builder.js - Dynamic theme generation system
class SyntaxThemeBuilder {
constructor() {
this.themes = new Map();
this.customProperties = new Map();
this.activeTheme = null;
this.initializeDefaultThemes();
}
initializeDefaultThemes() {
// GitHub-inspired theme
this.addTheme('github', {
name: 'GitHub',
colors: {
background: '#ffffff',
foreground: '#24292e',
selection: '#c8e1ff',
comment: '#6a737d',
keyword: '#d73a49',
string: '#032f62',
number: '#005cc5',
operator: '#24292e',
function: '#6f42c1',
variable: '#e36209',
type: '#005cc5',
tag: '#22863a',
attribute: '#6f42c1',
punctuation: '#24292e',
lineNumbers: '#959da5',
lineHighlight: '#f6f8fa',
border: '#e1e4e8',
scrollbar: '#d1d5da'
},
fonts: {
code: "'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', 'Courier', monospace"
},
sizes: {
fontSize: '14px',
lineHeight: '1.45'
}
});
// VS Code Dark+ theme
this.addTheme('vscode-dark', {
name: 'VS Code Dark+',
colors: {
background: '#1e1e1e',
foreground: '#d4d4d4',
selection: '#264f78',
comment: '#6a9955',
keyword: '#569cd6',
string: '#ce9178',
number: '#b5cea8',
operator: '#d4d4d4',
function: '#dcdcaa',
variable: '#9cdcfe',
type: '#4ec9b0',
tag: '#569cd6',
attribute: '#92c5f8',
punctuation: '#d4d4d4',
lineNumbers: '#858585',
lineHighlight: '#2a2d2e',
border: '#3c3c3c',
scrollbar: '#424242'
},
fonts: {
code: "'Fira Code', 'Cascadia Code', 'JetBrains Mono', 'Consolas', monospace"
},
sizes: {
fontSize: '14px',
lineHeight: '1.4'
}
});
// Material Design theme
this.addTheme('material', {
name: 'Material Design',
colors: {
background: '#263238',
foreground: '#eeffff',
selection: '#546e7a',
comment: '#546e7a',
keyword: '#c792ea',
string: '#c3e88d',
number: '#f78c6c',
operator: '#89ddff',
function: '#82aaff',
variable: '#eeffff',
type: '#ffcb6b',
tag: '#f07178',
attribute: '#c792ea',
punctuation: '#89ddff',
lineNumbers: '#546e7a',
lineHighlight: '#314549',
border: '#37474f',
scrollbar: '#37474f'
},
fonts: {
code: "'Operator Mono', 'Fira Code', 'SF Mono', monospace"
},
sizes: {
fontSize: '14px',
lineHeight: '1.5'
}
});
}
addTheme(id, themeConfig) {
this.themes.set(id, themeConfig);
}
generateThemeCSS(themeId) {
const theme = this.themes.get(themeId);
if (!theme) {
throw new Error(`Theme '${themeId}' not found`);
}
const { colors, fonts, sizes } = theme;
return `
/* ${theme.name} Theme */
.theme-${themeId} {
--syntax-bg: ${colors.background};
--syntax-fg: ${colors.foreground};
--syntax-selection: ${colors.selection};
--syntax-comment: ${colors.comment};
--syntax-keyword: ${colors.keyword};
--syntax-string: ${colors.string};
--syntax-number: ${colors.number};
--syntax-operator: ${colors.operator};
--syntax-function: ${colors.function};
--syntax-variable: ${colors.variable};
--syntax-type: ${colors.type};
--syntax-tag: ${colors.tag};
--syntax-attribute: ${colors.attribute};
--syntax-punctuation: ${colors.punctuation};
--syntax-line-numbers: ${colors.lineNumbers};
--syntax-line-highlight: ${colors.lineHighlight};
--syntax-border: ${colors.border};
--syntax-scrollbar: ${colors.scrollbar};
--syntax-font: ${fonts.code};
--syntax-font-size: ${sizes.fontSize};
--syntax-line-height: ${sizes.lineHeight};
}
.theme-${themeId} pre[class*="language-"] {
background: var(--syntax-bg);
color: var(--syntax-fg);
font-family: var(--syntax-font);
font-size: var(--syntax-font-size);
line-height: var(--syntax-line-height);
border: 1px solid var(--syntax-border);
}
.theme-${themeId} code[class*="language-"] {
background: var(--syntax-bg);
color: var(--syntax-fg);
font-family: var(--syntax-font);
}
.theme-${themeId} .token.comment,
.theme-${themeId} .token.prolog,
.theme-${themeId} .token.doctype,
.theme-${themeId} .token.cdata {
color: var(--syntax-comment);
}
.theme-${themeId} .token.punctuation {
color: var(--syntax-punctuation);
}
.theme-${themeId} .token.property,
.theme-${themeId} .token.tag,
.theme-${themeId} .token.boolean,
.theme-${themeId} .token.constant,
.theme-${themeId} .token.symbol,
.theme-${themeId} .token.deleted {
color: var(--syntax-tag);
}
.theme-${themeId} .token.number {
color: var(--syntax-number);
}
.theme-${themeId} .token.selector,
.theme-${themeId} .token.attr-name,
.theme-${themeId} .token.string,
.theme-${themeId} .token.char,
.theme-${themeId} .token.builtin,
.theme-${themeId} .token.inserted {
color: var(--syntax-string);
}
.theme-${themeId} .token.operator,
.theme-${themeId} .token.entity,
.theme-${themeId} .token.url,
.theme-${themeId} .language-css .token.string,
.theme-${themeId} .style .token.string {
color: var(--syntax-operator);
}
.theme-${themeId} .token.atrule,
.theme-${themeId} .token.attr-value,
.theme-${themeId} .token.keyword {
color: var(--syntax-keyword);
}
.theme-${themeId} .token.function,
.theme-${themeId} .token.class-name {
color: var(--syntax-function);
}
.theme-${themeId} .token.regex,
.theme-${themeId} .token.important,
.theme-${themeId} .token.variable {
color: var(--syntax-variable);
}
.theme-${themeId} .token.namespace {
color: var(--syntax-type);
}
.theme-${themeId} .line-numbers .line-numbers-rows {
border-right-color: var(--syntax-border);
}
.theme-${themeId} .line-numbers-rows > span:before {
color: var(--syntax-line-numbers);
}
.theme-${themeId} .line-highlight {
background: var(--syntax-line-highlight);
}
.theme-${themeId} pre[class*="language-"]::-webkit-scrollbar {
width: 12px;
height: 12px;
}
.theme-${themeId} pre[class*="language-"]::-webkit-scrollbar-track {
background: var(--syntax-bg);
}
.theme-${themeId} pre[class*="language-"]::-webkit-scrollbar-thumb {
background: var(--syntax-scrollbar);
border-radius: 6px;
}
.theme-${themeId} pre[class*="language-"]::-webkit-scrollbar-thumb:hover {
background: color-mix(in srgb, var(--syntax-scrollbar), white 20%);
}
.theme-${themeId} ::selection {
background: var(--syntax-selection);
}
`;
}
applyTheme(themeId) {
// Remove existing theme stylesheets
const existingThemes = document.querySelectorAll('style[data-syntax-theme]');
existingThemes.forEach(style => style.remove());
// Apply new theme
const css = this.generateThemeCSS(themeId);
const style = document.createElement('style');
style.setAttribute('data-syntax-theme', themeId);
style.textContent = css;
document.head.appendChild(style);
// Update body class
document.body.classList.remove(...Array.from(document.body.classList).filter(cls => cls.startsWith('theme-')));
document.body.classList.add(`theme-${themeId}`);
this.activeTheme = themeId;
// Store preference
localStorage.setItem('preferred-syntax-theme', themeId);
// Emit theme change event
document.dispatchEvent(new CustomEvent('syntaxThemeChanged', {
detail: { themeId, theme: this.themes.get(themeId) }
}));
}
createCustomTheme(id, baseThemeId, overrides = {}) {
const baseTheme = this.themes.get(baseThemeId);
if (!baseTheme) {
throw new Error(`Base theme '${baseThemeId}' not found`);
}
const customTheme = {
name: overrides.name || `Custom ${baseTheme.name}`,
colors: { ...baseTheme.colors, ...overrides.colors },
fonts: { ...baseTheme.fonts, ...overrides.fonts },
sizes: { ...baseTheme.sizes, ...overrides.sizes }
};
this.addTheme(id, customTheme);
return id;
}
getAvailableThemes() {
return Array.from(this.themes.entries()).map(([id, theme]) => ({
id,
name: theme.name
}));
}
exportTheme(themeId) {
const theme = this.themes.get(themeId);
if (!theme) {
throw new Error(`Theme '${themeId}' not found`);
}
return {
id: themeId,
...theme
};
}
importTheme(themeData) {
const { id, ...theme } = themeData;
this.addTheme(id, theme);
return id;
}
// Color utility methods
lighten(color, amount) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * amount);
const R = (num >> 16) + amt;
const G = (num >> 8 & 0x00FF) + amt;
const B = (num & 0x0000FF) + amt;
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
}
darken(color, amount) {
return this.lighten(color, -amount);
}
hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
}
// Theme selector component
class ThemeSelector {
constructor(themeBuilder, containerId) {
this.themeBuilder = themeBuilder;
this.container = document.getElementById(containerId);
if (this.container) {
this.createSelector();
this.loadSavedTheme();
}
}
createSelector() {
const selector = document.createElement('select');
selector.id = 'syntax-theme-selector';
selector.className = 'theme-selector';
selector.setAttribute('aria-label', 'Select syntax highlighting theme');
const label = document.createElement('label');
label.htmlFor = 'syntax-theme-selector';
label.textContent = 'Syntax Theme: ';
label.className = 'theme-selector-label';
const themes = this.themeBuilder.getAvailableThemes();
themes.forEach(theme => {
const option = document.createElement('option');
option.value = theme.id;
option.textContent = theme.name;
selector.appendChild(option);
});
selector.addEventListener('change', (e) => {
this.themeBuilder.applyTheme(e.target.value);
});
this.container.appendChild(label);
this.container.appendChild(selector);
this.selector = selector;
}
loadSavedTheme() {
const savedTheme = localStorage.getItem('preferred-syntax-theme');
if (savedTheme && this.themeBuilder.themes.has(savedTheme)) {
this.selector.value = savedTheme;
this.themeBuilder.applyTheme(savedTheme);
} else {
// Apply default theme based on system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const defaultTheme = prefersDark ? 'vscode-dark' : 'github';
this.selector.value = defaultTheme;
this.themeBuilder.applyTheme(defaultTheme);
}
}
}
// Initialize theme system
const themeBuilder = new SyntaxThemeBuilder();
// Auto-initialize if container exists
document.addEventListener('DOMContentLoaded', function() {
const themeContainer = document.getElementById('theme-selector-container');
if (themeContainer) {
new ThemeSelector(themeBuilder, 'theme-selector-container');
}
// Listen for system theme changes
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeQuery.addListener(function(e) {
if (!localStorage.getItem('preferred-syntax-theme')) {
const autoTheme = e.matches ? 'vscode-dark' : 'github';
themeBuilder.applyTheme(autoTheme);
}
});
});
```
## Language-Specific Highlighting Extensions
### Custom Language Definitions
```javascript
// custom-languages.js - Extended language support
class CustomLanguageDefinitions {
constructor(prismInstance) {
this.Prism = prismInstance;
this.defineCustomLanguages();
}
defineCustomLanguages() {
this.defineDockerfile();
this.defineNginxConfig();
this.defineEnvFiles();
this.defineLogFormats();
this.defineConfigFormats();
this.defineBashWithPrompt();
this.defineJSONWithComments();
this.defineMarkdownWithMeta();
}
defineDockerfile() {
this.Prism.languages.dockerfile = {
'comment': {
pattern: /#.*/,
greedy: true
},
'instruction': {
pattern: /^\s*(?:FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ARG|ONBUILD|STOPSIGNAL|HEALTHCHECK|SHELL)\b/im,
alias: 'keyword'
},
'string': {
pattern: /"(?:[^"\\]|\\.)*"/,
greedy: true
},
'variable': /\$(?:\w+|\{[^}]*\})/,
'operator': /&&|\|\||[<>]=?|[!=]=|[&|]|\+\+?|--?|\*\*?|\/\/?|%|\^|[?:~]/,
'punctuation': /[{}[\];(),.:]/
};
this.Prism.languages.docker = this.Prism.languages.dockerfile;
}
defineNginxConfig() {
this.Prism.languages.nginx = {
'comment': /#.*/,
'directive': {
pattern: /\b(?:server|location|upstream|proxy_pass|listen|server_name|root|index|try_files|error_page|access_log|error_log|gzip|ssl_certificate|ssl_certificate_key|return|rewrite|if|set|add_header|expires|client_max_body_size|worker_processes|events|http|stream)\b/,
alias: 'keyword'
},
'variable': /\$[a-zA-Z_][a-zA-Z0-9_]*/,
'string': {
pattern: /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/,
greedy: true
},
'boolean': /\b(?:on|off)\b/,
'number': /\b\d+(?:\.\d+)?[kmg]?\b/i,
'operator': /[=~]/,
'punctuation': /[{};\[\]]/
};
}
defineEnvFiles() {
this.Prism.languages.env = {
'comment': /#.*/,
'variable': {
pattern: /^[A-Z_][A-Z0-9_]*(?=\s*=)/m,
alias: 'property'
},
'value': {
pattern: /=.*/,
inside: {
'string': {
pattern: /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/,
greedy: true
},
'variable': /\$\{?[A-Z_][A-Z0-9_]*\}?/,
'number': /\b\d+(?:\.\d+)?\b/,
'boolean': /\b(?:true|false|yes|no|on|off)\b/i
}
},
'operator': /=/
};
this.Prism.languages.dotenv = this.Prism.languages.env;
this.Prism.languages.envfile = this.Prism.languages.env;
}
defineLogFormats() {
this.Prism.languages.log = {
'timestamp': {
pattern: /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?(?:Z|[+-]\d{2}:\d{2})?|\[?\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2}(?: [+-]\d{4})?\]?/m,
alias: 'number'
},
'level': {
pattern: /\b(?:TRACE|DEBUG|INFO|WARN|WARNING|ERROR|FATAL|CRITICAL|EMERGENCY|ALERT)\b/i,
alias: 'keyword'
},
'ip': {
pattern: /\b(?:\d{1,3}\.){3}\d{1,3}\b/,
alias: 'number'
},
'url': {
pattern: /https?:\/\/[^\s]+/,
alias: 'string'
},
'status': {
pattern: /\b[1-5]\d{2}\b/,
alias: 'number'
},
'string': {
pattern: /"(?:[^"\\]|\\.)*"/,
greedy: true
},
'uuid': {
pattern: /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i,
alias: 'variable'
}
};
}
defineConfigFormats() {
this.Prism.languages.ini = {
'comment': /^[;#].*/m,
'section': {
pattern: /^\[[^\]]*\]/m,
alias: 'keyword'
},
'property': {
pattern: /^[^=\r\n]+(?=\s*=)/m,
alias: 'attr-name'
},
'value': {
pattern: /=.*/,
inside: {
'string': {
pattern: /"(?:[^"\\]|\\.)*"/,
greedy: true
},
'number': /\b\d+(?:\.\d+)?\b/,
'boolean': /\b(?:true|false|yes|no|on|off)\b/i
}
},
'operator': /=/
};
this.Prism.languages.config = this.Prism.languages.ini;
this.Prism.languages.cfg = this.Prism.languages.ini;
}
defineBashWithPrompt() {
this.Prism.languages['bash-prompt'] = this.Prism.util.clone(this.Prism.languages.bash);
this.Prism.languages['bash-prompt']['prompt'] = {
pattern: /^[$#]\s*/m,
alias: 'keyword'
};
this.Prism.languages['bash-session'] = {
'command': {
pattern: /^[$#]\s*[^\r\n]*$/m,
inside: {
'prompt': {
pattern: /^[$#]\s*/,
alias: 'keyword'
},
'bash': {
pattern: /[\s\S]+/,
alias: 'language-bash',
inside: this.Prism.languages.bash
}
}
},
'output': {
pattern: /^(?![$#]\s)[^\r\n]*$/m,
alias: 'string'
}
};
}
defineJSONWithComments() {
this.Prism.languages.jsonc = this.Prism.util.clone(this.Prism.languages.json);
this.Prism.languages.jsonc.comment = {
pattern: /\/\/.*|\/\*[\s\S]*?\*\//,
greedy: true
};
this.Prism.languages['json5'] = this.Prism.util.clone(this.Prism.languages.jsonc);
// JSON5 additional features
this.Prism.languages.json5.property = {
pattern: /(?:[a-zA-Z_$][a-zA-Z0-9_$]*|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")(?=\s*:)/,
greedy: true,
alias: 'property'
};
}
defineMarkdownWithMeta() {
this.Prism.languages['markdown-meta'] = this.Prism.util.clone(this.Prism.languages.markdown);
this.Prism.languages['markdown-meta']['frontmatter'] = {
pattern: /^---[\s\S]*?---/,
inside: {
'punctuation': /^---|---$/m,
'yaml': {
pattern: /[\s\S]+(?=\r?\n---$)/,
alias: 'language-yaml',
inside: this.Prism.languages.yaml
}
}
};
// Enhanced code block highlighting
this.Prism.languages['markdown-meta']['code-block'] = {
pattern: /```[\s\S]*?```/,
inside: {
'code-info': {
pattern: /```[a-z]*(?:\{[^}]*\})?/,
alias: 'keyword'
},
'code': {
pattern: /[\s\S]+?(?=```$)/,
alias: 'language-markup'
},
'punctuation': /```/
}
};
}
// Utility method to register all languages at once
registerAll() {
Object.keys(this).forEach(method => {
if (method.startsWith('define') && typeof this[method] === 'function') {
this[method]();
}
});
}
}
// Auto-register custom languages when Prism is available
document.addEventListener('DOMContentLoaded', function() {
if (typeof Prism !== 'undefined') {
new CustomLanguageDefinitions(Prism);
}
});
```
## Interactive Code Examples
### Live Code Execution
```html
<!-- interactive-examples.html -->
<div class="interactive-code-example" data-language="javascript">
<div class="code-tabs">
<button class="tab active" data-tab="code">Code</button>
<button class="tab" data-tab="result">Result</button>
<button class="tab" data-tab="console">Console</button>
</div>
<div class="tab-content">
<div class="tab-pane active" data-pane="code">
<textarea class="code-editor" spellcheck="false">
// Interactive JavaScript Example
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// Calculate first 10 Fibonacci numbers
for (let i = 0; i < 10; i++) {
console.log(`F(${i}) = ${fibonacci(i)}`);
}
// Display result in page
const result = fibonacci(8);
document.body.innerHTML += `<h3>F(8) = ${result}</h3>`;
</textarea>
</div>
<div class="tab-pane" data-pane="result">
<iframe class="result-frame" sandbox="allow-scripts"></iframe>
</div>
<div class="tab-pane" data-pane="console">
<div class="console-output"></div>
</div>
</div>
<div class="code-controls">
<button class="run-button">▶ Run Code</button>
<button class="reset-button">Reset</button>
<button class="share-button">Share</button>
</div>
</div>
<script>
class InteractiveCodeExample {
constructor(container) {
this.container = container;
this.language = container.dataset.language || 'javascript';
this.codeEditor = container.querySelector('.code-editor');
this.resultFrame = container.querySelector('.result-frame');
this.consoleOutput = container.querySelector('.console-output');
this.originalCode = this.codeEditor.value;
this.initializeTabs();
this.initializeControls();
this.initializeEditor();
this.setupConsoleRedirect();
}
initializeTabs() {
const tabs = this.container.querySelectorAll('.tab');
const panes = this.container.querySelectorAll('.tab-pane');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const targetTab = tab.dataset.tab;
// Update tab states
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Update pane visibility
panes.forEach(pane => {
if (pane.dataset.pane === targetTab) {
pane.classList.add('active');
} else {
pane.classList.remove('active');
}
});
});
});
}
initializeControls() {
const runButton = this.container.querySelector('.run-button');
const resetButton = this.container.querySelector('.reset-button');
const shareButton = this.container.querySelector('.share-button');
runButton.addEventListener('click', () => this.runCode());
resetButton.addEventListener('click', () => this.resetCode());
shareButton.addEventListener('click', () => this.shareCode());
// Auto-run on code change (debounced)
let autoRunTimeout;
this.codeEditor.addEventListener('input', () => {
clearTimeout(autoRunTimeout);
autoRunTimeout = setTimeout(() => {
this.runCode();
}, 1000);
});
}
initializeEditor() {
// Add syntax highlighting to textarea
this.codeEditor.addEventListener('input', () => {
this.updateSyntaxHighlighting();
});
// Add keyboard shortcuts
this.codeEditor.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case 'Enter':
e.preventDefault();
this.runCode();
break;
case 'r':
e.preventDefault();
this.resetCode();
break;
}
}
// Handle tab indentation
if (e.key === 'Tab') {
e.preventDefault();
const start = this.codeEditor.selectionStart;
const end = this.codeEditor.selectionEnd;
const value = this.codeEditor.value;
this.codeEditor.value = value.substring(0, start) + ' ' + value.substring(end);
this.codeEditor.selectionStart = this.codeEditor.selectionEnd = start + 4;
}
});
// Initial syntax highlighting
this.updateSyntaxHighlighting();
}
updateSyntaxHighlighting() {
if (typeof Prism !== 'undefined' && Prism.languages[this.language]) {
const code = this.codeEditor.value;
const highlighted = Prism.highlight(code, Prism.languages[this.language], this.language);
// Update background highlighting (would need additional implementation)
this.updateEditorBackground(highlighted);
}
}
setupConsoleRedirect() {
// Create console proxy for capturing output
this.consoleLogs = [];
const originalLog = console.log;
const originalError = console.error;
const originalWarn = console.warn;
window.interceptConsole = (method, ...args) => {
this.consoleLogs.push({
method: method,
args: args,
timestamp: new Date()
});
this.updateConsoleDisplay();
// Call original method
if (method === 'log') originalLog(...args);
else if (method === 'error') originalError(...args);
else if (method === 'warn') originalWarn(...args);
};
}
runCode() {
try {
this.clearConsole();
this.clearResult();
if (this.language === 'javascript') {
this.runJavaScript();
} else if (this.language === 'html') {
this.runHTML();
} else if (this.language === 'css') {
this.runCSS();
}
} catch (error) {
this.showError(error);
}
}
runJavaScript() {
const code = this.codeEditor.value;
// Create sandbox environment
const sandboxCode = `
(function() {
const console = {
log: (...args) => parent.interceptConsole('log', ...args),
error: (...args) => parent.interceptConsole('error', ...args),
warn: (...args) => parent.interceptConsole('warn', ...args)
};
try {
${code}
} catch (error) {
console.error(error.message);
}
})();
`;
// Execute in iframe
const frameDoc = this.resultFrame.contentDocument || this.resultFrame.contentWindow.document;
frameDoc.open();
frameDoc.write(`
<html>
<head>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 16px;
line-height: 1.6;
}
h1, h2, h3 { margin-top: 0; }
</style>
</head>
<body>
<script>${sandboxCode}</script>
</body>
</html>
`);
frameDoc.close();
}
runHTML() {
const code = this.codeEditor.value;
const frameDoc = this.resultFrame.contentDocument || this.resultFrame.contentWindow.document;
frameDoc.open();
frameDoc.write(code);
frameDoc.close();
}
runCSS() {
const code = this.codeEditor.value;
const frameDoc = this.resultFrame.contentDocument || this.resultFrame.contentWindow.document;
frameDoc.open();
frameDoc.write(`
<html>
<head>
<style>${code}</style>
</head>
<body>
<div class="demo-content">
<h1>CSS Demo</h1>
<p>This is a paragraph to demonstrate your CSS.</p>
<button>Sample Button</button>
<div class="box">Sample Box</div>
</div>
</body>
</html>
`);
frameDoc.close();
}
clearConsole() {
this.consoleLogs = [];
this.updateConsoleDisplay();
}
clearResult() {
const frameDoc = this.resultFrame.contentDocument || this.resultFrame.contentWindow.document;
frameDoc.open();
frameDoc.write('<html><body></body></html>');
frameDoc.close();
}
updateConsoleDisplay() {
this.consoleOutput.innerHTML = '';
this.consoleLogs.forEach(log => {
const logElement = document.createElement('div');
logElement.className = `console-${log.method}`;
const timestamp = document.createElement('span');
timestamp.className = 'console-timestamp';
timestamp.textContent = log.timestamp.toLocaleTimeString();
const message = document.createElement('span');
message.className = 'console-message';
message.textContent = log.args.join(' ');
logElement.appendChild(timestamp);
logElement.appendChild(message);
this.consoleOutput.appendChild(logElement);
});
// Auto-scroll to bottom
this.consoleOutput.scrollTop = this.consoleOutput.scrollHeight;
}
showError(error) {
this.consoleLogs.push({
method: 'error',
args: [error.message],
timestamp: new Date()
});
this.updateConsoleDisplay();
}
resetCode() {
this.codeEditor.value = this.originalCode;
this.clearConsole();
this.clearResult();
this.updateSyntaxHighlighting();
}
shareCode() {
const code = this.codeEditor.value;
const shareData = {
language: this.language,
code: code
};
// Create shareable URL
const shareUrl = this.createShareUrl(shareData);
if (navigator.share) {
navigator.share({
title: 'Code Example',
text: 'Check out this code example',
url: shareUrl
});
} else {
// Fallback: copy to clipboard
navigator.clipboard.writeText(shareUrl).then(() => {
this.showShareFeedback();
});
}
}
createShareUrl(data) {
const encoded = btoa(JSON.stringify(data));
return `${window.location.origin}${window.location.pathname}?code=${encoded}`;
}
showShareFeedback() {
const feedback = document.createElement('div');
feedback.className = 'share-feedback';
feedback.textContent = 'Share URL copied to clipboard!';
this.container.appendChild(feedback);
setTimeout(() => {
feedback.classList.add('show');
}, 10);
setTimeout(() => {
feedback.classList.remove('show');
setTimeout(() => {
this.container.removeChild(feedback);
}, 300);
}, 2000);
}
}
// CSS for interactive examples
const interactiveExampleStyles = `
.interactive-code-example {
margin: 2rem 0;
border: 1px solid #e1e4e8;
border-radius: 8px;
background: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.code-tabs {
display: flex;
background: #f6f8fa;
border-bottom: 1px solid #e1e4e8;
border-radius: 8px 8px 0 0;
overflow: hidden;
}
.code-tabs .tab {
background: none;
border: none;
padding: 12px 20px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
color: #586069;
border-bottom: 3px solid transparent;
transition: all 0.2s ease;
}
.code-tabs .tab:hover {
background: #e1e4e8;
color: #24292e;
}
.code-tabs .tab.active {
background: #ffffff;
color: #24292e;
border-bottom-color: #007bff;
}
.tab-content {
position: relative;
min-height: 300px;
}
.tab-pane {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
padding: 16px;
}
.tab-pane.active {
display: block;
}
.code-editor {
width: 100%;
height: 100%;
min-height: 250px;
border: none;
outline: none;
resize: vertical;
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
font-size: 14px;
line-height: 1.5;
tab-size: 4;
background: transparent;
color: inherit;
}
.result-frame {
width: 100%;
height: 250px;
border: 1px solid #e1e4e8;
border-radius: 4px;
background: white;
}
.console-output {
height: 250px;
overflow-y: auto;
border: 1px solid #e1e4e8;
border-radius: 4px;
background: #1e1e1e;
color: #d4d4d4;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 13px;
padding: 8px;
}
.console-output div {
margin: 2px 0;
display: flex;
align-items: center;
gap: 8px;
}
.console-timestamp {
color: #858585;
font-size: 11px;
min-width: 80px;
}
.console-log {
color: #d4d4d4;
}
.console-error {
color: #f48771;
}
.console-warn {
color: #dcdcaa;
}
.code-controls {
display: flex;
gap: 8px;
padding: 12px 16px;
background: #f6f8fa;
border-top: 1px solid #e1e4e8;
border-radius: 0 0 8px 8px;
}
.code-controls button {
padding: 8px 16px;
border: 1px solid #e1e4e8;
border-radius: 4px;
background: white;
color: #24292e;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.code-controls button:hover {
background: #f3f4f6;
border-color: #d0d7de;
}
.run-button {
background: #2ea043 !important;
color: white !important;
border-color: #2ea043 !important;
}
.run-button:hover {
background: #2c974b !important;
}
.share-feedback {
position: absolute;
top: 8px;
right: 8px;
background: #28a745;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
opacity: 0;
transform: translateY(-10px);
transition: all 0.3s ease;
z-index: 1000;
}
.share-feedback.show {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 768px) {
.code-tabs {
flex-wrap: wrap;
}
.code-tabs .tab {
flex: 1;
min-width: 0;
padding: 10px 12px;
font-size: 13px;
}
.tab-pane {
padding: 12px;
}
.code-editor {
font-size: 13px;
}
.code-controls {
flex-wrap: wrap;
gap: 6px;
padding: 10px 12px;
}
.code-controls button {
flex: 1;
min-width: 0;
font-size: 13px;
padding: 8px 12px;
}
}
`;
// Inject styles
const style = document.createElement('style');
style.textContent = interactiveExampleStyles;
document.head.appendChild(style);
// Initialize all interactive examples
document.addEventListener('DOMContentLoaded', function() {
const examples = document.querySelectorAll('.interactive-code-example');
examples.forEach(example => {
new InteractiveCodeExample(example);
});
});
</script>
Integration with Documentation Systems
Advanced syntax highlighting integrates seamlessly with modern documentation workflows. When combined with table data validation systems, code highlighting ensures technical accuracy while maintaining visual consistency across complex documentation that includes both tabular data and code examples.
For comprehensive technical writing, syntax highlighting works effectively with accessibility compliance systems to ensure code examples remain readable for users with visual impairments while supporting screen readers and assistive technologies through proper semantic markup and high-contrast themes.
When building sophisticated documentation platforms, syntax highlighting complements content filtering and search capabilities by enabling searchable code indices, syntax-aware filtering, and intelligent code discovery that helps users find relevant programming examples across large technical documentation repositories.
Performance Optimization and Best Practices
Lazy Loading Implementation
// lazy-syntax-highlighting.js - Performance-optimized code highlighting
class LazySyntaxHighlighter {
constructor(options = {}) {
this.options = {
threshold: 0.1,
rootMargin: '50px',
enableVirtualization: true,
chunkSize: 50,
enableWorker: true,
...options
};
this.observer = null;
this.highlightQueue = [];
this.isProcessing = false;
this.worker = null;
this.init();
}
init() {
this.setupIntersectionObserver();
this.setupWorker();
this.observeCodeBlocks();
this.bindEvents();
}
setupIntersectionObserver() {
if ('IntersectionObserver' in window) {
this.observer = new IntersectionObserver(
this.handleIntersection.bind(this),
{
threshold: this.options.threshold,
rootMargin: this.options.rootMargin
}
);
}
}
setupWorker() {
if (this.options.enableWorker && 'Worker' in window) {
const workerScript = `
importScripts('https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js');
const languages = new Map();
self.addEventListener('message', async function(e) {
const { id, code, language, action } = e.data;
if (action === 'highlight') {
try {
if (!languages.has(language)) {
await loadLanguage(language);
}
const highlighted = Prism.highlight(code, Prism.languages[language], language);
self.postMessage({
id: id,
highlighted: highlighted,
success: true
});
} catch (error) {
self.postMessage({
id: id,
error: error.message,
success: false
});
}
}
});
async function loadLanguage(language) {
if (languages.has(language)) return;
try {
importScripts(\`https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-\${language}.min.js\`);
languages.set(language, true);
} catch (error) {
console.warn('Failed to load language:', language);
}
}
`;
const blob = new Blob([workerScript], { type: 'application/javascript' });
this.worker = new Worker(URL.createObjectURL(blob));
this.worker.addEventListener('message', (e) => {
this.handleWorkerMessage(e.data);
});
}
}
observeCodeBlocks() {
const codeBlocks = document.querySelectorAll('pre[class*="language-"], code[class*="language-"]');
codeBlocks.forEach(block => {
if (this.observer) {
this.observer.observe(block);
} else {
// Fallback for browsers without IntersectionObserver
this.highlightBlock(block);
}
});
}
handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.highlightBlock(entry.target);
this.observer.unobserve(entry.target);
}
});
}
highlightBlock(block) {
if (block.dataset.highlighted === 'true') return;
const code = block.textContent;
const language = this.extractLanguage(block);
if (this.options.enableVirtualization && code.length > 5000) {
this.highlightLargeBlock(block, code, language);
} else if (this.worker && code.length > 1000) {
this.highlightWithWorker(block, code, language);
} else {
this.highlightSynchronously(block, code, language);
}
block.dataset.highlighted = 'true';
}
highlightSynchronously(block, code, language) {
if (typeof Prism !== 'undefined' && Prism.languages[language]) {
const highlighted = Prism.highlight(code, Prism.languages[language], language);
this.applyHighlighting(block, highlighted);
}
}
highlightWithWorker(block, code, language) {
if (!this.worker) {
this.highlightSynchronously(block, code, language);
return;
}
const id = this.generateId();
block.dataset.highlightId = id;
this.worker.postMessage({
id: id,
code: code,
language: language,
action: 'highlight'
});
}
highlightLargeBlock(block, code, language) {
// Implement virtual scrolling for very large code blocks
const lines = code.split('\n');
const visibleLines = 100; // Show first 100 lines initially
if (lines.length <= visibleLines) {
this.highlightSynchronously(block, code, language);
return;
}
// Create virtual scrolling container
const container = this.createVirtualContainer(block);
const visibleCode = lines.slice(0, visibleLines).join('\n');
if (typeof Prism !== 'undefined' && Prism.languages[language]) {
const highlighted = Prism.highlight(visibleCode, Prism.languages[language], language);
this.applyHighlighting(container.codeElement, highlighted);
}
// Add load more functionality
this.setupLazyLoading(container, lines, language, visibleLines);
}
createVirtualContainer(originalBlock) {
const container = document.createElement('div');
container.className = 'virtual-code-container';
const codeElement = document.createElement('code');
codeElement.className = originalBlock.className;
const loadMoreButton = document.createElement('button');
loadMoreButton.textContent = 'Load More Lines';
loadMoreButton.className = 'load-more-code';
const pre = document.createElement('pre');
pre.className = originalBlock.className;
pre.appendChild(codeElement);
container.appendChild(pre);
container.appendChild(loadMoreButton);
originalBlock.parentNode.replaceChild(container, originalBlock);
return {
container: container,
codeElement: codeElement,
loadMoreButton: loadMoreButton,
pre: pre
};
}
setupLazyLoading(virtualContainer, allLines, language, currentlyVisible) {
const { loadMoreButton, codeElement } = virtualContainer;
let visibleCount = currentlyVisible;
const loadIncrement = 50;
loadMoreButton.addEventListener('click', () => {
const nextBatch = allLines.slice(visibleCount, visibleCount + loadIncrement);
if (nextBatch.length > 0) {
const batchCode = nextBatch.join('\n');
if (typeof Prism !== 'undefined' && Prism.languages[language]) {
const highlighted = Prism.highlight(batchCode, Prism.languages[language], language);
// Append highlighted code
const span = document.createElement('span');
span.innerHTML = '\n' + highlighted;
codeElement.appendChild(span);
}
visibleCount += loadIncrement;
if (visibleCount >= allLines.length) {
loadMoreButton.style.display = 'none';
} else {
loadMoreButton.textContent = `Load More Lines (${allLines.length - visibleCount} remaining)`;
}
}
});
// Initially hide button if all lines are visible
if (visibleCount >= allLines.length) {
loadMoreButton.style.display = 'none';
} else {
loadMoreButton.textContent = `Load More Lines (${allLines.length - visibleCount} remaining)`;
}
}
handleWorkerMessage(data) {
const { id, highlighted, success, error } = data;
if (success) {
const block = document.querySelector(`[data-highlight-id="${id}"]`);
if (block) {
this.applyHighlighting(block, highlighted);
}
} else {
console.warn('Worker highlighting failed:', error);
}
}
applyHighlighting(element, highlighted) {
// Use requestIdleCallback for better performance
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
element.innerHTML = highlighted;
});
} else {
// Fallback for browsers without requestIdleCallback
setTimeout(() => {
element.innerHTML = highlighted;
}, 0);
}
}
extractLanguage(element) {
const className = element.className;
const match = className.match(/language-([a-zA-Z0-9-]+)/);
return match ? match[1] : 'markup';
}
generateId() {
return Math.random().toString(36).substring(2, 15);
}
bindEvents() {
// Handle dynamically added code blocks
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
const codeBlocks = node.querySelectorAll('pre[class*="language-"], code[class*="language-"]');
codeBlocks.forEach(block => {
if (this.observer) {
this.observer.observe(block);
} else {
this.highlightBlock(block);
}
});
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// Performance monitoring
measurePerformance(operation, callback) {
const start = performance.now();
const result = callback();
const end = performance.now();
console.log(`${operation}: ${(end - start).toFixed(2)}ms`);
return result;
}
// Cleanup
destroy() {
if (this.observer) {
this.observer.disconnect();
}
if (this.worker) {
this.worker.terminate();
}
}
}
// Performance monitoring styles
const performanceStyles = `
.virtual-code-container {
position: relative;
max-height: 500px;
overflow: hidden;
border: 1px solid #e1e4e8;
border-radius: 6px;
}
.load-more-code {
width: 100%;
padding: 12px;
background: #f6f8fa;
border: none;
border-top: 1px solid #e1e4e8;
color: #24292e;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background-color 0.2s ease;
}
.load-more-code:hover {
background: #e1e4e8;
}
.load-more-code:focus {
outline: 2px solid #007bff;
outline-offset: -2px;
}
.code-performance-indicator {
position: absolute;
top: 8px;
left: 8px;
background: rgba(0,0,0,0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
font-family: monospace;
opacity: 0.7;
pointer-events: none;
}
/* Loading states */
.code-loading {
position: relative;
opacity: 0.6;
}
.code-loading::after {
content: 'Highlighting...';
position: absolute;
top: 8px;
right: 8px;
background: rgba(0,0,0,0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
z-index: 10;
}
/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
.code-loading,
.load-more-code {
transition: none;
}
}
`;
// Inject performance styles
const perfStyle = document.createElement('style');
perfStyle.textContent = performanceStyles;
document.head.appendChild(perfStyle);
// Initialize lazy highlighting
document.addEventListener('DOMContentLoaded', function() {
new LazySyntaxHighlighter({
enableVirtualization: true,
enableWorker: true,
threshold: 0.1,
rootMargin: '100px'
});
});
Conclusion
Advanced Markdown code syntax highlighting represents a fundamental component of modern technical documentation that significantly enhances code readability, user engagement, and knowledge transfer effectiveness. By implementing comprehensive highlighting systems, custom theme development, and interactive code examples, technical writers can create documentation experiences that effectively communicate complex programming concepts while maintaining accessibility and performance standards.
The key to successful syntax highlighting implementation lies in balancing visual enhancement with practical functionality, ensuring that highlighting systems improve rather than complicate the documentation experience. Whether you’re building API documentation, programming tutorials, or technical specifications, the techniques covered in this guide provide the foundation for creating professional-grade code presentation that serves both novice and expert developers.
Remember to implement highlighting progressively, prioritize accessibility across all themes, and optimize performance for large codebases. With proper advanced syntax highlighting implementation, your Markdown documentation becomes a powerful platform for technical communication that engages readers while effectively conveying complex programming information through visually rich, interactive code examples.