Skip to content

Code Blocks

Material for MkDocs provides extensive features for displaying code with syntax highlighting, line numbers, annotations, and more.

Overview

Code block features include:

  • Syntax highlighting - 190+ language support
  • Line numbers - Optional line numbering
  • Line highlighting - Emphasize specific lines
  • Code annotations - Inline explanations
  • Copy button - One-click copying
  • Title bars - File names and descriptions
  • Diff highlighting - Show changes
  • Code selection - Select specific lines

Basic Configuration

Enable code features in mkdocs.yml:

theme:
  features:
    - content.code.copy      # Copy button
    - content.code.select    # Line selection
    - content.code.annotate  # Code annotations

markdown_extensions:
  - pymdownx.highlight:
      anchor_linenums: true
      line_spans: __span
      pygments_lang_class: true
  - pymdownx.inlinehilite
  - pymdownx.superfences

Syntax Highlighting

Basic Usage

```python
def hello_world():
    print("Hello, World!")
```

Result:

def hello_world():
    print("Hello, World!")

Supported Languages

Common languages: - python, py - Python - javascript, js - JavaScript - typescript, ts - TypeScript - bash, sh - Shell scripts - yaml, yml - YAML - json - JSON - markdown, md - Markdown - html - HTML - css - CSS - sql - SQL

Inline Code

Highlight inline code with specific language:

The `#!python print()` function outputs text.

Result: The print() function outputs text.

Line Numbers

Enable Line Numbers

```python linenums="1"
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
```

Result:

1
2
3
4
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Custom Starting Number

```python linenums="10"
    return result  # Line 10
}  # Line 11
```

Line Highlighting

Highlight Specific Lines

```python hl_lines="2 4"
def calculate_area(radius):
    pi = 3.14159  # Highlighted
    area = pi * radius ** 2
    return area  # Highlighted
```

Result:

def calculate_area(radius):
    pi = 3.14159  # Highlighted
    area = pi * radius ** 2
    return area  # Highlighted

Highlight Ranges

```python hl_lines="2-4 6"
def process_data(data):
    # Validation - highlighted block
    if not data:
        raise ValueError("No data")

    # Processing - single line highlight
    result = transform(data)
    return result
```

Code Annotations

Basic Annotations

```python
def greet(name):
    print(f"Hello, {name}!")  # (1)!

# Call the function
greet("World")  # (2)!
```

1. This creates a personalized greeting
2. Output: Hello, World!

Result:

def greet(name):
    print(f"Hello, {name}!")  # (1)!

# Call the function
greet("World")  # (2)!

  1. This creates a personalized greeting
  2. Output: Hello, World!

Rich Annotations

Annotations can contain any Markdown:

```python
import requests  # (1)!

response = requests.get("https://api.github.com")  # (2)!
```

1. :material-package-down: Install with `pip install requests`
2. !!! warning

    Always handle exceptions when making HTTP requests:
    ```python
    try:
        response = requests.get(url)
        response.raise_for_status()
    except requests.RequestException as e:
        print(f"Error: {e}")
    ```

Title and Filename

Add Title

```python title="fibonacci.py"
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
```

With Line Numbers

```python title="app.py" linenums="1"
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return "Hello, World!"
```

Copy Button

The copy button is automatically added when enabled:

theme:
  features:
    - content.code.copy

Features: - Appears on hover - Copies clean code (no line numbers) - Shows confirmation - Keyboard accessible

Custom Copy Button Text

/* Change copy button text */
.md-clipboard::before {
  content: "Copy to clipboard";
}

.md-clipboard--inline::before {
  content: "Copy";
}

Diff Highlighting

Show Changes

def hello_world():
-    print("Hello World")
+    print("Hello, World!")

With Syntax Highlighting

```python hl_lines="3 5"
def calculate_total(items):
    total = 0
-   for item in items:
+   for i, item in enumerate(items):
-       total += item
+       total += item * (i + 1)
    return total
```

Advanced Features

Code Groups with Tabs

# Python implementation
def greet(name):
    return f"Hello, {name}!"
// JavaScript implementation
function greet(name) {
    return `Hello, ${name}!`;
}
// Go implementation
func greet(name string) string {
    return fmt.Sprintf("Hello, %s!", name)
}

Nested Code Blocks

Using SuperFences:

def generate_markdown():
    return """
    # Title

    ```python
    print("Nested code block")
    ```

    More content...
    """

Custom Lexers

For unsupported languages:

```text
This is plain text without highlighting
but still formatted as code
```

Styling

Custom Theme

/* docs/assets/stylesheets/code.css */

/* Code block background */
.md-typeset pre {
  background-color: #1e1e1e;
}

/* Syntax highlighting colors */
.highlight .k {  /* Keywords */
  color: #569cd6;
}

.highlight .s {  /* Strings */
  color: #ce9178;
}

.highlight .c {  /* Comments */
  color: #6a9955;
}

/* Line highlighting */
.highlight .hll {
  background-color: #3d4752;
  display: block;
  margin: 0 -1em;
  padding: 0 1em;
}

/* Line numbers */
.highlight .linenos {
  color: #858585;
  margin-right: 1em;
  user-select: none;
}

Responsive Design

/* Mobile-friendly code blocks */
@media screen and (max-width: 768px) {
  .md-typeset pre {
    border-radius: 0;
    margin: 0 -0.8rem;
  }

  .highlight {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

Configuration Options

Highlight Configuration

markdown_extensions:
  - pymdownx.highlight:
      anchor_linenums: true     # Anchor line numbers
      line_spans: __span        # Line span classes
      pygments_lang_class: true # Add language class
      use_pygments: true        # Use Pygments
      auto_title: false         # Auto-generate titles
      linenums_style: pymdownx-inline  # Line number style

SuperFences Configuration

markdown_extensions:
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid
          format: !!python/name:pymdownx.superfences.fence_code_format
      preserve_tabs: true       # Preserve tab characters

Best Practices

1. Language Specification

Always specify the language:

❌ ```
   code without language
   ```

✅ ```python
   # Python code with highlighting
   ```

2. Meaningful Examples

Provide complete, runnable examples:

# Complete example
import json

def load_config(filename):
    """Load configuration from JSON file."""
    with open(filename, 'r') as f:
        return json.load(f)

# Usage
config = load_config('config.json')
print(config['api_key'])

3. Appropriate Line Highlighting

Highlight only important lines:

def process_user_data(user_id):
    # Fetch user data
    user = get_user(user_id)

    # Important: Validate before processing
    if not user.is_active:
        raise ValueError("User is not active")

    # Process the data
    return transform_data(user)

4. Useful Annotations

Add context with annotations:

services:
  web:
    build: .  # (1)!
    ports:
      - "8000:8000"  # (2)!
    environment:
      - DEBUG=1  # (3)!
  1. Build from current directory
  2. Map host port 8000 to container port 8000
  3. Enable debug mode in development

Integration

With mkdocstrings

Code examples in docstrings:

def calculate_discount(price: float, discount: float) -> float:
    """Calculate discounted price.

    Example:
        ```python
        >>> calculate_discount(100, 0.2)
        80.0
        ```
    """
    return price * (1 - discount)

With Jupyter Notebooks

Notebook code cells are automatically highlighted:

# This appears in a Jupyter notebook
import pandas as pd
df = pd.read_csv('data.csv')
df.head()

Accessibility

Code blocks include:

  • Proper ARIA labels
  • Keyboard navigation
  • Screen reader support
  • High contrast themes
  • Copy button accessibility

Performance

Large Code Blocks

For very large code blocks:

  1. Consider using collapsible sections
  2. Load code asynchronously
  3. Use virtualization for thousands of lines

Syntax Highlighting Performance

markdown_extensions:
  - pymdownx.highlight:
      guess_lang: false  # Disable language guessing
      use_pygments: true # Faster than JavaScript

Examples

API Documentation

api/users.py
from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    """Get user by ID."""
    # Fetch user from database
    user = db.get_user(user_id)  # (1)!

    if not user:
        return jsonify({'error': 'User not found'}), 404

    return jsonify(user.to_dict())
  1. Replace db.get_user() with your database query

Configuration Files

docker-compose.yml
version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:14
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass

See Also