Code Block

Code people read or copy: an API request, a webhook's payload, a config file, a log excerpt, an embed snippet. A <pre><code> in a frame, with a title and a copy button. Specification: docs/components/code-block.md

Basics

A .canon-code-block around a <pre><code>. A .canon-code-block-header first holds a .canon-code-block-title (a file name, or what the code is) and its buttons: usually a Button with command="--canon-copy", whose commandfor names the <code>. It copies the code's text, without the highlighting.

invoice.paid.json
{
  "id": "evt_1Q2w3E",
  "type": "invoice.paid",
  "created": "2026-10-16T09:24:11Z",
  "data": {
    "invoice": "INV-2041",
    "amount": 129000,
    "currency": "EUR",
    "paid": true,
    "coupon": null
  }
}

Without a header

For a short snippet, leave out the header: the copy button goes after the <pre>, and sits in the code's top corner. It is the right corner in every language, where lines end, since code reads left to right.

curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"

Highlighting

Canon doesn't highlight code; do it before the page is sent (on the server or at build time) and put the result inside the <code>. Themes color tokens by twinkleplop's names: <span class="tok string">, tok keyword, tok tag_name and so on. Code without tokens is plain text, which suits logs and keys.

These docs use twinkleplop for their own code: the examples on this page were highlighted ahead of time, and the Playground's HTML and the code in these notes are highlighted in the browser with @twinkleplop/html. Any highlighter works, as long as its tokens get those class names.

Embed code
<script src="https://cdn.example.com/widget.js" defer></script>
<div class="support-widget" data-team="billing"></div>
Test API key
sk_live_51Mx0Lq2eZvKYlo2C8f3Hj7Wn4rTb9QpXa6Yd

Long code

Code keeps its lines and scrolls in its box, sideways and, with --canon-code-block-max-height, down. A box that scrolls becomes a region named by the title (or "Code"), so keyboards can reach and scroll it.

deploy.yaml
# Billing worker, production
service: billing-worker
image: registry.example.com/billing-worker:2.14.0
replicas: 3
resources:
  cpu: 500m
  memory: 512Mi
env:
  - name: QUEUE_URL
    value: amqps://queue.internal:5671/billing
  - name: RETRY_LIMIT
    value: "5"
  - name: LOG_LEVEL
    value: info
healthcheck:
  path: /healthz
  interval: 10s
  timeout: 2s
schedule:
  - cron: "0 3 * * *"
    task: reconcile-payouts
  - cron: "*/15 * * * *"
    task: retry-failed-charges

Wrapping

Long lines scroll by default, so columns stay aligned. A wrap button in the header, before the copy button, lets people wrap them instead: a Button with command="--canon-wrap", named "Wrap lines", whose aria-pressed is the state. Start it pressed (aria-pressed="true") where wrapped reads better, as for logs on a narrow screen.

billing-worker.log
2026-10-16 09:24:11.482 INFO  [billing-worker-3] invoice.paid INV-2041 amount=1290.00 EUR customer=cus_8XkP2 attempt=1 latency_ms=184 trace=4bf92f3577b34da6a3ce929d0e0e4736
2026-10-16 09:24:12.007 WARN  [billing-worker-1] charge.retry INV-2038 reason=card_declined decline_code=insufficient_funds attempt=3 next_retry=2026-10-16T09:39:12Z
2026-10-16 09:24:12.311 INFO  [billing-worker-3] payout.created po_3Ld81 amount=48210.55 EUR destination=acct_1Mx0 arrival=2026-10-18
billing-worker.log, starts wrapped
2026-10-16 09:24:11.482 INFO  [billing-worker-3] invoice.paid INV-2041 amount=1290.00 EUR customer=cus_8XkP2 attempt=1 latency_ms=184 trace=4bf92f3577b34da6a3ce929d0e0e4736
2026-10-16 09:24:12.007 WARN  [billing-worker-1] charge.retry INV-2038 reason=card_declined decline_code=insufficient_funds attempt=3 next_retry=2026-10-16T09:39:12Z
2026-10-16 09:24:12.311 INFO  [billing-worker-3] payout.created po_3Ld81 amount=48210.55 EUR destination=acct_1Mx0 arrival=2026-10-18

Size

data-size on the block or a container sets the code's type and spacing. Its buttons take the size they're given.

Small
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"
Medium (default)
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"
Large
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"

Edge cases

A long title is cut (…). In right-to-left pages the header follows the page while the code stays left to right.

Fetch one invoice with its line items, payments, refunds, credit notes and the customer it belongs to (sandbox account)
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"
طلب فاتورة
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"
curl https://api.example.com/v1/invoices/INV-2041 \
  -H "Authorization: Bearer $API_TOKEN"