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>.
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.
<x-wirekit::button>Save</x-wirekit::button>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.
composer require pushery/wirekit
php artisan wirekit:installWith Filename
Pass filename="…" to render a subtle header bar above the code. Useful for showing file paths or command-line contexts.
Route::get('/', function () {
return view('welcome');
});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".
composer require pushery/wirekitWith 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.
use Pushery\WireKit\WireKit;
public function boot(): void
{
WireKit::scope('marketing', [
'button' => ['classes' => ['base' => 'rounded-full']],
]);
}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:
# 1. highlight.js is a developer-side choice — WireKit only emits the
# data-language="…" hook attribute the highlighter targets.
npm install highlight.js
// 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.
Do not alias blade to php-template:
// 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. |
label |
string|null |
null |
Names the scrollable code region, and the switch that makes it a screen-reader landmark. Without it the block stays keyboard-reachable and simply is not a landmark — see Accessibility. |
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 for block-level class overrides. |
Accessibility
- The copy button is a real
<button>element and reachable viaTab - 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 - The
<code>carriestabindex="0"in every configuration, so a keyboard user can reach text that scrolled out of view (WCAG 2.1.1)
The landmark is opt-in — name the block to get one
A named region is a landmark, and landmarks have to be distinguishable. The component used
to derive a name from the language, which read well on a page with one or two blocks and badly
on a page with twenty of the same language: the name meant to tell them apart was the thing that
made them identical, and an accessibility audit reports it as landmark-unique.
So an unnamed block is not a landmark at all. It keeps tabindex="0" and its focus ring, which
is what keyboard reachability actually requires — nothing a screen-reader user could have acted
on is lost, because an unnamed entry in a list of twenty was never a way to find anything.
Pass label when the block IS worth navigating to, and name it after what it contains rather
than after what it is:
{{-- 1. "Change 4471" locates the block; "php code" only repeats what the page already is. --}}
{{-- 2. One name per instance — the rotor lists them all, in order. --}}
@foreach ($changes as $change)
<x-wirekit::code-block language="php" :label="__('Change :id', ['id' => $change->id])">
{{ $change->diff }}
</x-wirekit::code-block>
@endforeach
An empty or whitespace-only label counts as no name — a role="region" with an empty
accessible name is not exposed as a landmark anyway, so the block omits the role rather than
shipping one nobody can identify. An interpolated value over a record with no title lands here.
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 — inline monospace for running text
- Customization —
WireKit::scope()for block-level class overrides