---
title: Code Block
description: Multi-line code block with copy button
visibility: guest
draft: false
---

# Code Block

A multi-line code block with monospace rendering, optional filename header, copy-to-clipboard button, and language attribute for future syntax highlighting. For inline code inside running text, use [`<x-wirekit::code>`](./code.md).

## Live Sandbox

This is a hydrated playground for the component. Toggle "Live preview" on the block below to swap the static HTML render for a real Livewire instance — every prop in the component's sandbox schema becomes an editable form field inside the iframe, so you can try different prop combinations live without writing any local code.

:::preview{title="Sandbox" sandbox="code-block" props='{"language":"blade","body":"<x-wirekit::button>Save</x-wirekit::button>"}'}
<x-wirekit::code-block language="blade">&lt;x-wirekit::button&gt;Save&lt;/x-wirekit::button&gt;</x-wirekit::code-block>
:::

## Basic Usage

Wrap any code snippet in `<x-wirekit::code-block>`. The body is rendered verbatim inside a `<pre><code>` pair using the `--font-wk-mono` font token.

:::preview{title="Plain code block"}
<x-wirekit::code-block>composer require pushery/wirekit
php artisan wirekit:install</x-wirekit::code-block>
:::

## With Filename

Pass `filename="…"` to render a subtle header bar above the code. Useful for showing file paths or command-line contexts.

:::preview{title="Code block with filename"}
<x-wirekit::code-block filename="routes/web.php">Route::get('/', function () {
    return view('welcome');
});</x-wirekit::code-block>
:::

## With Copy Button

Set `:copy="true"` to add a copy-to-clipboard button in the header bar. The button uses `navigator.clipboard.writeText()` and shows a checkmark for two seconds after a successful copy. The button is always accessible via keyboard and exposes `aria-label="Copy to clipboard"`.

:::preview{title="Copyable code block"}
<x-wirekit::code-block :copy="true" filename="Install">composer require pushery/wirekit</x-wirekit::code-block>
:::

## With Language

Pass `language="…"` to emit a `data-language="..."` attribute on the `<code>` element. The component itself does not ship a syntax highlighter — the attribute is a hook for developer-side highlighters (Prism, Shiki, highlight.js) to pick up.

:::preview{title="Code block with language"}
<x-wirekit::code-block :copy="true" language="php" filename="app/Providers/AppServiceProvider.php">use Pushery\WireKit\WireKit;

public function boot(): void
{
    WireKit::scope('marketing', [
        'button' => ['classes' => ['base' => 'rounded-full']],
    ]);
}</x-wirekit::code-block>
:::

### Blade syntax highlighting

highlight.js does **not** ship a built-in `blade` language module. Its built-in `php-template` language covers most Laravel-Blade idioms (`@directive`, `{{ }}`, `{!! !!}`, mixed HTML+PHP) — but it delegates HTML to hljs's `xml` mode, whose tag-name matcher is `[A-Za-z0-9_.-]+` and explicitly does NOT accept `:`. Under a `php-template` alias, a `<x-wirekit::button>` tag tokenizes as `<x-wirekit:` + bare `:` + orphan `:button>` — visibly broken on every WireKit component example.

The fix is a tiny custom grammar that extends hljs's XML-tag rule with `::` support. Drop this in the same module where you call `hljs.registerLanguage(...)`. WireKit ships no highlighter, so install the one you want first:

```bash
# 1. highlight.js is a developer-side choice — WireKit only emits the
#    data-language="…" hook attribute the highlighter targets.
npm install highlight.js
```

```javascript
// 1. Load highlight.js + the languages you use.
import hljs from 'highlight.js/lib/core';
import xml from 'highlight.js/lib/languages/xml';
import php from 'highlight.js/lib/languages/php';

hljs.registerLanguage('xml', xml);
hljs.registerLanguage('php', php);

// 2. Register a custom `blade` grammar that handles `::` in tag names.
//    Covers @directives, {{ }} echoes, {!! !!} raw, and HTML/component
//    tags with the WireKit namespace separator.
hljs.registerLanguage('blade', function (hljs) {
    const BLADE_COMMENT = { className: 'comment', begin: /\{\{--/, end: /--\}\}/ };
    const BLADE_RAW     = { className: 'template-variable', begin: /\{!!/, end: /!!\}/ };
    const BLADE_ECHO    = { className: 'template-variable', begin: /\{\{/,  end: /\}\}/  };
    const BLADE_DIR     = { className: 'keyword',           begin: /@[a-zA-Z]+/ };
    const TAG = {
        className: 'tag',
        begin: /<\/?/, end: /\/?>/,
        contains: [
            // The `::` is the load-bearing change vs. stock xml/php-template —
            // it lets `<x-wirekit::button>` tokenize as one tag name.
            { className: 'name',   begin: /[\w.::-]+/, relevance: 0 },
            { className: 'attr',   begin: /[\w-]+/ },
            { className: 'string', begin: /"/, end: /"/ },
            { className: 'string', begin: /'/, end: /'/ },
        ],
    };
    return {
        name: 'Blade',
        case_insensitive: true,
        contains: [BLADE_COMMENT, BLADE_RAW, BLADE_ECHO, BLADE_DIR, TAG],
    };
});

// 3. Highlight all code blocks on the page.
hljs.highlightAll();
```

Without that grammar a `<code class="language-blade">` block falls through to highlight.js's no-highlight fallback (you'll see a console warning `Could not find the language 'blade'`) — the block still renders as plain monospace text, it just doesn't get colored tokens.

::: warning
Do not alias `blade` to `php-template`:

```javascript
// Don't do this — looks tempting, breaks WireKit components.
hljs.registerAliases('blade', { languageName: 'php-template' });
```

`php-template` covers Blade directives and interpolations but its underlying XML mode treats `:` as a tag-name boundary. Every `x-wirekit::*` example then renders with broken tokens — the component prefix splits off and the rest of the line reads as orphan text. The 30-line custom grammar above is the smallest fix that keeps WireKit's `::` namespace separator intact.
:::

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `language` | `string\|null` | `null` | Emitted as `data-language` on the `<code>` tag — hook for developer syntax highlighters. |
| `filename` | `string\|null` | `null` | Text shown in the header bar. When set, the header bar is rendered even without `copy`. |
| `copy` | `bool` | `false` | Show a copy-to-clipboard button in the header bar. |
| `scope` | `string\|null` | `null` | Named [personalization scope](/customization) for block-level class overrides. |

## Accessibility

- The copy button is a real `<button>` element and reachable via `Tab`
- The icon-only button exposes `aria-label="Copy to clipboard"` and updates to `"Copied to clipboard"` after a successful copy
- An `aria-live="polite"` status region announces `"Code copied to clipboard"` to screen readers on success (WCAG 2.2 SC 4.1.3)
- The success state swap is a visual-only change — the button is never removed from the tab order
- The underlying `<pre>` block is horizontally scrollable on overflow, with a visible focus outline when reached by keyboard

## Keyboard Interaction

This component is purely presentational and does not respond to keyboard input.

## Design Tokens

| Token | Used for |
| --- | --- |
| `--font-wk-mono` | Monospace font family |
| `--color-wk-bg-muted` | Code block background |
| `--color-wk-border` | Wrapper + header-bar border |
| `--color-wk-text` | Code color |
| `--color-wk-text-muted` | Filename and copy-button color |
| `--color-wk-success` | Copy-success checkmark color |
| `--radius-wk-md` | Wrapper border radius |
| `--text-wk-sm` | Code font size |
| `--text-wk-xs` | Filename font size |
| `--space-wk-md` | Code padding |
| `--space-wk-xs` | Header-bar vertical padding |

## See Also

- [Code](./code.md) — inline monospace for running text
- [Customization](/customization) — `WireKit::scope()` for block-level class overrides
