HTML <pre> and <code> reference Jump to this section

Common attributes Jump to this section

Basic structures Jump to this section

<pre> preserves whitespace and line breaks exactly as written in HTML, rendering text in a monospace font. <code> marks up a fragment of computer code inline. They are most powerful when combined: <pre><code> is the standard pattern for displaying multi-line code blocks.

Key difference: Use <code> alone for inline code snippets within prose. Use <pre><code> together for freestanding multi-line code blocks.

Inline: use console.log() to debug.

function greet(name) {
  return "Hello, " + name;
}
<!-- Inline code -->
<p>Use <code>console.log()</code> to debug.</p>

<!-- Block code --> <pre><code>function greet(name) { return "Hello, " + name; }</code></pre>

Pre attributes Jump to this section

Whitespace preservation Jump to this section

<pre> renders text exactly as typed: spaces, tabs, and newlines are all preserved. This is its defining behavior and requires no attribute (it is built in).

Note: Content inside <pre> must have special HTML characters escaped (&lt; for <, &gt; for >, &amp; for &). When inserting code via JavaScript, use textContent rather than innerHTML to handle this automatically.

  indented
    further
        even more
<pre>  indented
    further
        even more</pre>

ASCII art and diagrams Jump to this section

<pre> is ideal for ASCII art, text diagrams, and any content where spatial positioning matters.

┌───────────┐
│  Client   │
└─────┬─────┘
      │ HTTP
┌─────▼─────┐
│  Server   │
└───────────┘
<pre>
┌───────────┐
│  Client   │
└─────┬─────┘
      │ HTTP
┌─────▼─────┐
│  Server   │
└───────────┘
</pre>

width (deprecated) Jump to this section

The width attribute was used to set the maximum number of characters per line. It is deprecated, use CSS instead.

<!-- Deprecated, don't use -->
<pre width="40">...</pre>

<!-- Use CSS instead -->
<pre style="max-width: 40ch;">...</pre>

wrap (non-standard) Jump to this section

A non-standard attribute in some older browsers. Use CSS white-space instead for wrapping behavior.

<!-- Use CSS instead -->
<pre style="white-space: pre-wrap;">Long line that should wrap...</pre>

Code attributes Jump to this section

class (for language hints) Jump to this section

The most important attribute on <code> when inside a <pre> block. Syntax highlighting libraries like Prism.js and Highlight.js use a language-* class to identify the language and apply appropriate coloring.

Use language-* for Prism.js or just the language name for Highlight.js.

const x = 42;
<!-- Prism.js -->
<pre><code class="language-javascript">
const x = 42;
</code></pre>

<!-- Highlight.js --> <pre><code class="javascript"> const x = 42; </code></pre>

<!-- Other common values --> <code class="language-html"> <code class="language-css"> <code class="language-python"> <code class="language-bash"> <code class="language-json"> <code class="language-sql">

Inline code Jump to this section

Inline <code> in prose Jump to this section

Use <code> alone (without <pre>) for short inline references to variable names, function names, file paths, keyboard shortcuts, or any technical term.

Call Array.isArray() to check the type.
The config lives at /etc/nginx/nginx.conf.
Press Ctrl+S to save.

<p>Call <code>Array.isArray()</code>
to check the type.</p>

<p>The config lives at <code>/etc/nginx/nginx.conf</code>.</p>

<p>Press <code>Ctrl+S</code> to save.</p>

<kbd> Jump to this section

Represents keyboard input. Use for documenting keyboard shortcuts and key combinations, distinct from <code> which represents program output or code.

Press Ctrl + C to copy.

<p>Press <kbd>Ctrl</kbd> + <kbd>C</kbd>
to copy.</p>

<samp> Jump to this section

Represents sample output from a computer program. Use to display what a program prints or returns.

The program outputs: Hello, world!

<p>The program outputs:
<samp>Hello, world!</samp></p>

<var> Jump to this section

Represents a variable in a mathematical expression or programming context.

The area equals width × height.

<p>The area equals
<var>width</var> × <var>height</var>.</p>

Accessibility attributes Jump to this section

aria-label Jump to this section

Provides an accessible label for a code block when more context is useful for screen reader users.

<pre aria-label="JavaScript example showing array destructuring">
<code class="language-javascript">
const [a, b] = [1, 2];
</code>
</pre>

aria-describedby Jump to this section

References explanatory text by id to give screen reader users additional context about a code block.

<p id="snippet-desc">This function returns the sum of two numbers.</p>
<pre aria-describedby="snippet-desc"><code>
function add(a, b) {
  return a + b;
}
</code></pre>

role="region" with aria-label Jump to this section

Wrap code blocks in a <figure> or <section> with a label to give them landmark semantics.

<figure aria-label="Code example">
    <pre><code class="language-js">const x = 1;</code></pre>
    <figcaption>Declaring a constant in JavaScript</figcaption>
</figure>

tabindex Jump to this section

Adding tabindex="0" to a <pre> makes it focusable with the keyboard, which is useful for long scrollable code blocks so keyboard users can scroll them.

<pre tabindex="0">
<code>...long code block...</code>
</pre>

Common attributes Jump to this section

id Jump to this section

Unique identifier. Useful for deep-linking to specific code examples and JavaScript targeting.

<pre id="installation-snippet">
<code class="language-bash">npm install my-package</code>
</pre>

<a href="#installation-snippet">See installation snippet</a>

class Jump to this section

Assigns CSS class names for styling or JavaScript selection. Also used by syntax highlighting libraries.

<pre class="code-block code-block--dark">
<code class="language-python">print("Hello")</code>
</pre>

data-* attributes Jump to this section

Custom attributes for storing metadata about a code block. Useful for copy buttons, language labels, and file names.

<pre data-language="javascript" data-filename="app.js" data-copyable="true">
<code class="language-javascript">const x = 1;</code>
</pre>

<script>
  const block = document.querySelector('pre');
  console.log(block.dataset.language); // "javascript"
  console.log(block.dataset.filename); // "app.js"
</script>

translate Jump to this section

Set to "no" to prevent translation services from translating the code content (since code should stay in its original language).

<pre translate="no">
<code class="language-python">def greet():
    print("Hello")</code>
</pre>

spellcheck Jump to this section

Set to "false" on editable code to prevent browser spell-check underlining in code editors.

<pre contenteditable="true" spellcheck="false">
<code>const myVariable = "hello";</code>
</pre>

Styling basics Jump to this section

<pre> and <code> carry minimal default browser styling, just a monospace font and whitespace preservation for <pre>. Most visual polish comes from CSS. The most common patterns are dark-theme code blocks, inline code pills, and copy-button wrappers.

Basic code block Jump to this section

function hello() {
  console.log("Hello, world!");
}
pre {
    background: #f3f4f6;
    padding: 16px;
    border-radius: 6px;
    font-size: 14px;
    overflow-x: auto;
}

pre code { font-family: 'Monaco', 'Menlo', 'Consolas', monospace; font-size: inherit; background: none; padding: 0; }

Dark theme Jump to this section

function hello() {
  console.log("Hello, world!");
}
pre {
    background: #1e1e1e;
    color: #d4d4d4;
    padding: 16px;
    border-radius: 8px;
    font-size: 14px;
    overflow-x: auto;
}

With top bar / filename Jump to this section

app.js
const express = require('express');
const app = express();

HTML Structure:

<div class="code-wrapper">
    <div class="code-header">app.js</div>
    <pre><code>const express = require('express');
const app = express();</code></pre>
</div>

CSS:

.code-wrapper {
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid #e5e7eb;
}

.code-header {
    background: #f3f4f6;
    padding: 8px 16px;
    font-size: 13px;
    color: #6b7280;
    border-bottom: 1px solid #e5e7eb;
    font-family: monospace;
}

.code-wrapper pre {
    margin: 0;
    border-radius: 0;
}

With language badge Jump to this section

JS
const x = 42;

HTML Structure:

<div class="code-wrapper">
    <span class="language-badge">JS</span>
    <pre><code>const x = 42;</code></pre>
</div>

CSS:

.code-wrapper {
    position: relative;
}

.language-badge {
    position: absolute;
    top: 10px;
    right: 12px;
    background: #3b82f6;
    color: white;
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 4px;
    font-family: monospace;
    font-weight: 600;
    letter-spacing: 0.5px;
}

With line numbers Jump to this section

1
2
3
4
function greet(name) {
  const msg = "Hello, " + name;
  return msg;
}

HTML Structure:

<div class="code-wrapper">
    <div class="line-numbers">
        1<br>2<br>3<br>4
    </div>
    <pre><code>function greet(name) {
  const msg = "Hello, " + name;
  return msg;
}</code></pre>
</div>

CSS:

.code-wrapper {
    display: flex;
    background: #1e1e1e;
    border-radius: 8px;
    overflow: hidden;
}

.line-numbers {
    background: #252526;
    color: #6b7280;
    padding: 16px 12px;
    text-align: right;
    user-select: none;
    line-height: 1.6;
}

.code-wrapper pre {
    margin: 0;
    color: #d4d4d4;
    padding: 16px;
    flex: 1;
}

With copy button Jump to this section

const x = 42;

HTML Structure:

<div class="code-wrapper">
    <button class="copy-btn">Copy</button>
    <pre><code>const x = 42;</code></pre>
</div>

CSS:

.code-wrapper {
    position: relative;
}

.copy-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 4px 10px;
    background: #374151;
    color: #d1d5db;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 12px;
    font-family: monospace;
    transition: background 0.2s;
}

.copy-btn:hover {
    background: #4b5563;
}

Light theme with border Jump to this section

const x = 42;
console.log(x);
pre {
    background: #fafafa;
    border: 1px solid #e5e7eb;
    border-left: 4px solid #3b82f6;
    padding: 16px;
    border-radius: 4px;
    font-size: 13px;
    overflow-x: auto;
}

Scrollable with max height Jump to this section

line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
pre {
    max-height: 200px;
    overflow-y: auto;
    overflow-x: auto;
}

/* Custom scrollbar */ pre::-webkit-scrollbar { height: 6px; width: 6px; }

pre::-webkit-scrollbar-track { background: #2d2d2d; }

pre::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; }

Inline code styles Jump to this section

Basic inline code Jump to this section

Call console.log() to debug.

code {
    background: #f3f4f6;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.875em;
    font-family: 'Monaco', 'Menlo', monospace;
    color: #374151;
}

Colored inline code Jump to this section

Use fetch() to call APIs.

Run npm install to set up.

Avoid eval() in production.

.code-blue {
    background: #dbeafe;
    color: #1e40af;
}

.code-green { background: #dcfce7; color: #166534; }

.code-red { background: #fee2e2; color: #991b1b; }

Inline code with border Jump to this section

Check the package.json file.

code {
    border: 1px solid #d1d5db;
    background: #fafafa;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.875em;
    font-family: monospace;
}

Keyboard key style Jump to this section

Press Ctrl + K to search.

kbd {
    border: 1px solid #d1d5db;
    border-bottom: 3px solid #9ca3af;
    background: #f9fafb;
    padding: 3px 8px;
    border-radius: 4px;
    font-family: monospace;
    font-size: 0.875em;
    color: #374151;
}

Block code extras Jump to this section

Highlighted line Jump to this section

function greet(name) {  return "Hello, " + name;}

HTML Structure:

<pre><code>
<span class="line">function greet(name) {</span>
<span class="line highlighted-line">  return "Hello, " + name;</span>
<span class="line">}</span>
</code></pre>

CSS:

/* Mark specific lines */
.line {
    display: block;
    padding: 4px 16px;
}

.highlighted-line {
    background: #264f78;
    border-left: 3px solid #569cd6;
    margin: 0 -16px;
    padding: 4px 13px; /* Adjust for border */
}

Diff style Jump to this section

+ const name = "Alice";- const name = "Bob";  console.log(name);

HTML Structure:

<pre><code>
<span class="diff-add">+ const name = "Alice";</span>
<span class="diff-remove">- const name = "Bob";</span>
<span class="diff-unchanged">  console.log(name);</span>
</code></pre>

CSS:

.diff-add {
    display: block;
    background: #1a3322;
    color: #4caf50;
    padding: 4px 16px;
}

.diff-remove {
    display: block;
    background: #3b1212;
    color: #f44336;
    padding: 4px 16px;
}

.diff-unchanged {
    display: block;
    padding: 4px 16px;
}

Responsive wrapping Jump to this section

/* Wrap long lines instead of horizontal scroll */
pre {
    white-space: pre-wrap;
    word-break: break-all;
}

/* Prefer scroll on wide screens, wrap on narrow */
@media (max-width: 640px) {
    pre {
        white-space: pre-wrap;
        word-break: break-word;
    }
}

JavaScript patterns Jump to this section

The most common JavaScript tasks for <pre> and <code> are copy-to-clipboard buttons, dynamic code insertion, syntax highlighting, and building interactive code editors.

Copy to clipboard Jump to this section

Add a copy button to every code block on the page.

const greeting = "Hello!";
console.log(greeting);

HTML Structure:

<div class="code-wrapper">
    <button id="copy-btn" class="copy-btn">Copy</button>
    <pre id="code-block"><code>const greeting = "Hello!";
console.log(greeting);</code></pre>
</div>

JavaScript:

// Single copy button
const btn = document.getElementById('copy-btn');
const block = document.getElementById('code-block');

btn.addEventListener('click', async () => {
    const text = block.querySelector('code').textContent;
    
    await navigator.clipboard.writeText(text);
    
    btn.textContent = 'Copied!';
    btn.style.background = '#10b981';
    
    setTimeout(() => {
        btn.textContent = 'Copy';
        btn.style.background = '#374151';
    }, 2000);
});

// Add copy buttons to every code block
document.querySelectorAll('pre').forEach(pre => {
    const btn = document.createElement('button');
    btn.textContent = 'Copy';
    btn.className = 'copy-btn';
    
    btn.addEventListener('click', async () => {
        const text = pre.querySelector('code').textContent;
        await navigator.clipboard.writeText(text);
        btn.textContent = 'Copied!';
        setTimeout(() => btn.textContent = 'Copy', 2000);
    });
    
    pre.style.position = 'relative';
    pre.appendChild(btn);
});

Insert code dynamically Jump to this section

Safely insert code content into a <pre><code> block.

// Click a button to insert code

HTML Structure:

<pre><code id="code">// Initial code</code></pre>

JavaScript:

const codeEl = document.getElementById('code');

// Safe insertion, textContent auto-escapes HTML entities
codeEl.textContent = `function add(a, b) {
  return a + b;
}`;

// Unsafe, only use if the code is already escaped
// codeEl.innerHTML = escapedHtmlString;

// Helper to safely set code from a string
function setCode(elementId, code) {
    document.getElementById(elementId).textContent = code;
}

Read code content Jump to this section

Extract the text content of a code block.

const pi = 3.14159;
const area = pi * r * r;
const pre = document.getElementById('code-block');

// Get code text const code = pre.querySelector('code').textContent;

// Get the language from the class const codeEl = pre.querySelector('code'); const langClass = Array.from(codeEl.classList) .find(c => c.startsWith('language-')); const language = langClass?.replace('language-', ''); // e.g. "javascript"

// Count lines const lineCount = code.split('\n').length; console.log(${lineCount} lines of ${language});

Add line numbers dynamically Jump to this section

Inject line numbers into existing code blocks with JavaScript.

function add(a, b) {
  return a + b;
}

const result = add(2, 3);

HTML Structure:

<pre id="code-block"><code>function add(a, b) {
  return a + b;
}

const result = add(2, 3);</code></pre>

JavaScript:

function addLineNumbers(preId) {
    const pre = document.getElementById(preId);
    const code = pre.querySelector('code');
    
    const lines = code.textContent.split('\n');
    // Remove trailing empty line if present
    if (lines[lines.length - 1] === '') lines.pop();
    
    code.innerHTML = lines.map((line, i) => {
        const num = String(i + 1).padStart(2, ' ');
        const escaped = line
            .replace(/&/g, '&')
            .replace(//g, '>');
        return `${num}${escaped}`;
    }).join('\n');
}

Highlight specific lines Jump to this section

Wrap specific lines in a highlight span after inserting code.

function greet(name) {
  const msg = "Hello, " + name;
  return msg;
}

HTML Structure:

<pre><code id="code">function greet(name) {
  const msg = "Hello, " + name;
  return msg;
}</code></pre>

JavaScript:

function highlightLines(codeId, linesToHighlight) {
    const code = document.getElementById(codeId);
    
    const lines = code.textContent.split('\n');
    if (lines[lines.length - 1] === '') lines.pop();
    
    code.innerHTML = lines.map((line, i) => {
        const lineNum = i + 1;
        const escaped = line
            .replace(/&/g, '&')
            .replace(//g, '>');
        
        if (linesToHighlight.includes(lineNum)) {
            return `${escaped}`;
        }
        return `${escaped}`;
    }).join('');
}

Simple editable code block Jump to this section

Make a code block editable using contenteditable.

// Edit me directly!
const x = 1 + 1;

HTML Structure:

<pre id="editable-pre" contenteditable="true" spellcheck="false">
<code>// Edit me directly!
const x = 1 + 1;</code>
</pre>

JavaScript:

const pre = document.getElementById('editable-pre');

// Make editable
pre.contentEditable = 'true';
pre.spellcheck = false;

// Focus styles
pre.addEventListener('focus', () => {
    pre.style.outline = '2px solid #3b82f6';
});
pre.addEventListener('blur', () => {
    pre.style.outline = '2px solid transparent';
});

// Read current content
pre.addEventListener('input', () => {
    const currentCode = pre.textContent;
    console.log('Code changed:', currentCode);
});

Detect language from class Jump to this section

Read the language identifier from a code block's class name.

function getLanguage(codeElement) {
    const classes = Array.from(codeElement.classList);
    
    // Prism.js: "language-javascript"
    const prismClass = classes.find(c => c.startsWith('language-'));
    if (prismClass) return prismClass.replace('language-', '');
    
    // Highlight.js: bare language name e.g. "javascript"
    const known = ['javascript', 'python', 'html', 'css',
                   'bash', 'json', 'typescript', 'sql'];
    return classes.find(c => known.includes(c)) ?? 'plaintext';
}

const code = document.querySelector('pre code');
console.log(getLanguage(code)); // "javascript"

Add copy buttons to all code blocks Jump to this section

Automatically wire up a copy button for every <pre> on the page.

function addCopyButtons() {
    document.querySelectorAll('pre').forEach(pre => {
        // Skip if already has a button
        if (pre.querySelector('.copy-btn')) return;
        
        const btn = document.createElement('button');
        btn.textContent = 'Copy';
        btn.className = 'copy-btn';
        
        Object.assign(btn.style, {
            position: 'absolute',
            top: '10px',
            right: '10px',
            padding: '4px 10px',
            background: '#374151',
            color: '#d1d5db',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer',
            fontSize: '12px',
            fontFamily: 'monospace',
        });
        
        btn.addEventListener('click', async () => {
            const code = pre.querySelector('code');
            const text = (code ?? pre).textContent;
            
            try {
                await navigator.clipboard.writeText(text);
                btn.textContent = '✓ Copied!';
                btn.style.background = '#10b981';
            } catch {
                btn.textContent = 'Failed';
                btn.style.background = '#ef4444';
            }
            
            setTimeout(() => {
                btn.textContent = 'Copy';
                btn.style.background = '#374151';
            }, 2000);
        });
        
        pre.style.position = 'relative';
        pre.appendChild(btn);
    });
}

// Run on load and after dynamic content changes
document.addEventListener('DOMContentLoaded', addCopyButtons);

Count and list all code blocks Jump to this section

Inspect and enumerate code blocks on the page.

// Get all code blocks and their languages
const blocks = Array.from(document.querySelectorAll('pre code'));

const summary = blocks.map((code, index) => {
    const langClass = Array.from(code.classList)
        .find(c => c.startsWith('language-'));
    const language = langClass?.replace('language-', '') ?? 'unknown';
    const lines = code.textContent.trim().split('\n').length;
    
    return { index, language, lines };
});

console.table(summary);
// ┌───────┬─────────────┬───────┐
// │ index │ language    │ lines │
// ├───────┼─────────────┼───────┤
// │ 0     │ javascript  │ 5     │
// │ 1     │ css         │ 8     │
// └───────┴─────────────┴───────┘

// Count by language
const byLanguage = summary.reduce((acc, { language }) => {
    acc[language] = (acc[language] ?? 0) + 1;
    return acc;
}, {});

console.log(byLanguage); // { javascript: 4, css: 2, html: 3 }

Wrap code blocks automatically Jump to this section

Find bare <pre> elements and wrap them with a styled container.

function wrapCodeBlocks() {
    document.querySelectorAll('pre:not(.wrapped)').forEach(pre => {
        const code = pre.querySelector('code');
        const langClass = code 
            ? Array.from(code.classList)
                .find(c => c.startsWith('language-'))
            : null;
        const language = langClass?.replace('language-', '');
        
        // Create wrapper
        const wrapper = document.createElement('div');
        wrapper.className = 'code-wrapper';
        
        // Create header if language is known
        if (language) {
            const header = document.createElement('div');
            header.className = 'code-header';
            header.textContent = language.toUpperCase();
            wrapper.appendChild(header);
        }
        
        // Insert wrapper in DOM
        pre.parentNode.insertBefore(wrapper, pre);
        wrapper.appendChild(pre);
        pre.classList.add('wrapped');
    });
}