Skip to content

Instantly share code, notes, and snippets.

@chrismytton
Created January 11, 2026 07:56
Show Gist options
  • Select an option

  • Save chrismytton/e81ab269a8c5539333e5bc72076e9cf7 to your computer and use it in GitHub Desktop.

Select an option

Save chrismytton/e81ab269a8c5539333e5bc72076e9cf7 to your computer and use it in GitHub Desktop.
Example of using Python's Pygments library in the browser via Pyodide
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pygments Syntax Highlighter</title>
<script src="https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #fafafa;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
min-height: 100vh;
}
.header {
padding: 40px 30px 30px;
border-bottom: 1px solid #e5e5e5;
}
.header h1 {
font-size: 24px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 6px;
letter-spacing: -0.5px;
}
.header p {
color: #666;
font-size: 15px;
font-weight: 400;
}
.controls {
padding: 20px 30px;
background: white;
border-bottom: 1px solid #e5e5e5;
display: flex;
gap: 24px;
flex-wrap: wrap;
align-items: center;
}
.control-group {
display: flex;
align-items: center;
gap: 10px;
}
.controls label {
font-weight: 500;
color: #666;
font-size: 14px;
}
.controls select {
padding: 6px 10px;
border: 1px solid #d4d4d4;
border-radius: 4px;
font-size: 14px;
background: white;
cursor: pointer;
color: #1a1a1a;
font-family: inherit;
}
.controls select:hover {
border-color: #a3a3a3;
}
.controls select:focus {
outline: none;
border-color: #666;
}
.content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
}
.editor-pane, .output-pane {
padding: 30px;
min-height: calc(100vh - 200px);
}
.editor-pane {
border-right: 1px solid #e5e5e5;
background: #fafafa;
}
.output-pane {
background: white;
}
.pane-title {
font-size: 12px;
font-weight: 500;
color: #999;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
textarea {
width: 100%;
height: calc(100vh - 280px);
min-height: 300px;
padding: 16px;
border: 1px solid #d4d4d4;
border-radius: 4px;
font-family: 'SF Mono', Monaco, 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
resize: vertical;
background: white;
color: #1a1a1a;
}
textarea:focus {
outline: none;
border-color: #666;
}
.output {
background: white;
border: 1px solid #d4d4d4;
border-radius: 4px;
padding: 16px;
height: calc(100vh - 280px);
min-height: 300px;
overflow: auto;
}
.output pre {
margin: 0;
font-size: 13px;
line-height: 1.6;
}
.loading {
color: #999;
font-size: 14px;
}
.error {
background: #fff5f5;
border: 1px solid #fecaca;
color: #dc2626;
padding: 12px;
border-radius: 4px;
font-size: 14px;
}
@media (max-width: 900px) {
.content {
grid-template-columns: 1fr;
}
.editor-pane {
border-right: none;
border-bottom: 1px solid #e5e5e5;
min-height: 400px;
}
.output-pane {
min-height: 400px;
}
textarea, .output {
height: 350px;
min-height: 350px;
}
.header {
padding: 24px 20px 20px;
}
.header h1 {
font-size: 20px;
}
.header p {
font-size: 14px;
}
.controls {
padding: 16px 20px;
gap: 16px;
}
.editor-pane, .output-pane {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎨 Pygments Syntax Highlighter</h1>
<p>Python's powerful syntax highlighter running in your browser</p>
</div>
<div class="controls">
<label for="language">Language:</label>
<select id="language">
<option value="python">Python</option>
<option value="javascript">JavaScript</option>
<option value="rust">Rust</option>
<option value="go">Go</option>
<option value="java">Java</option>
<option value="cpp">C++</option>
<option value="ruby">Ruby</option>
<option value="php">PHP</option>
<option value="sql">SQL</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="markdown">Markdown</option>
</select>
<label for="style">Style:</label>
<select id="style">
<option value="monokai">Monokai</option>
<option value="github-dark">GitHub Dark</option>
<option value="dracula">Dracula</option>
<option value="nord">Nord</option>
<option value="one-dark">One Dark</option>
<option value="solarized-dark">Solarized Dark</option>
<option value="solarized-light">Solarized Light</option>
<option value="gruvbox-dark">Gruvbox Dark</option>
</select>
</div>
<div class="content">
<div class="editor-pane">
<div class="pane-title">Input Code</div>
<textarea id="code">def fibonacci(n):
"""Generate Fibonacci sequence up to n terms."""
a, b = 0, 1
result = []
for _ in range(n):
result.append(a)
a, b = b, a + b
return result
# Calculate first 10 Fibonacci numbers
numbers = fibonacci(10)
print(f"First 10 Fibonacci numbers: {numbers}")</textarea>
</div>
<div class="output-pane">
<div class="pane-title">Highlighted Output</div>
<div id="output" class="output">
<div class="loading">Loading Pyodide...</div>
</div>
</div>
</div>
</div>
<script>
let pyodide;
async function initPyodide() {
try {
pyodide = await loadPyodide();
await pyodide.loadPackage("micropip");
const micropip = pyodide.pyimport("micropip");
await micropip.install('pygments');
document.getElementById('output').innerHTML = '<div class="loading">Ready! Type or select options to highlight code.</div>';
highlight();
} catch (err) {
document.getElementById('output').innerHTML = `<div class="error">Error loading Pyodide: ${err.message}</div>`;
}
}
async function highlight() {
if (!pyodide) return;
const code = document.getElementById('code').value;
const language = document.getElementById('language').value;
const style = document.getElementById('style').value;
try {
const result = await pyodide.runPythonAsync(`
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
code = """${code.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"""
lexer = get_lexer_by_name("${language}")
formatter = HtmlFormatter(style="${style}", full=False, cssclass="highlight")
# Get the CSS
css = formatter.get_style_defs('.highlight')
# Get the highlighted HTML
html = highlight(code, lexer, formatter)
# Return both as a tuple
(css, html)
`);
const [css, html] = result.toJs();
document.getElementById('output').innerHTML = `
<style>${css}</style>
${html}
`;
} catch (err) {
document.getElementById('output').innerHTML = `<div class="error">Error: ${err.message}</div>`;
}
}
// Event listeners
document.getElementById('code').addEventListener('input', highlight);
document.getElementById('language').addEventListener('change', highlight);
document.getElementById('style').addEventListener('change', highlight);
// Initialize
initPyodide();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment