Skip to content

CodeBlock

A headless, read-only code viewer with a copy button, an opt-in title and language header, decorative line numbers, and a Show-more collapse for long listings. It ships no syntax highlighter, so bring your own through the language class hook (client autoloaders) or the children escape hatch (build-time highlighters like Shiki).

Import

import { CodeBlock } from "@hyzer-labs/ui"

Demo

With no title and no language, the copy button floats over the top-right corner of the code.

function scoreToPar(round: { strokes: number }, par: number): number {
	return round.strokes - par;
}
<CodeBlock code={code} />

Props

NameTypeDefaultNote
codestringRequired. The source text. Copy, the line count, and the gutter always read from this, never from `children` or highlighter-injected markup.
childrenSnippetEscape hatch for pre-highlighted content, usually a build-time highlighter's own `<pre>` via `{@html}` (Shiki, for example). Replaces the default `<pre><code>` entirely; `code` is still required.
titlestringA filename or label. Renders the header bar, together with `language`.
languagestringStamps `class="language-<language>"` on the default code (the hook browser-side highlighters look for) and shows a visible, non-interactive tag in the header.
lineNumbersbooleanfalseOpt-in decorative line-number gutter. Never part of copy or selection.
copyablebooleantrueWhether the built-in copy button renders.
collapsiblebooleanfalseClamp tall listings behind a Show-more/less toggle.
collapsedLinesnumber16Rows shown while collapsed. The toggle appears only when the listing is longer than this.
classstringMerged after the hz-code-block class.

Theme hooks

What this component promises your CSS. The reference theme styles exactly these — from @layer hz-theme, so your unlayered rules win. See Styling Components for the how.

Root class: .hz-code-block

Data attributes

HookValuesStyles
data-language<string> — present when language is setMirrors the language prop; the default code also carries language-<value> for client autoloaders, and the header shows a matching tag.
data-has-titlepresent when title is setMarks the titled form. Independent of data-language — the header can render from either.
data-highlightedpresent when the children escape hatch is usedMarks a block whose code node is consumer-supplied pre-highlighted markup. Target it to drop the default code-surface fill and let a build-time highlighter's own background sit cleanly.
data-collapsiblepresent when the listing exceeds collapsedLinesReflects effective behaviour, not the raw prop — a short listing never gets the toggle, so this is absent for it.
data-line-numberspresent when lineNumbers is onMarks the gutter form.

Custom properties

HookValuesStyles
--hz-code-block-bg<color> — default var(--hz-color-surface-muted)The code surface fill; the collapse fade fades into it. Suppressed under data-highlighted so a build-time highlighter's own background shows.
--hz-code-block-padding<length> — default 1remPadding inside the code region (pre) — reaches a consumer-supplied pre too.
--hz-code-block-fade-height<length> — default 3remHeight of the collapse fade over the clamped edge.

Part classes

HookValuesStyles
.hz-code-block-headerchild elementThe header bar; present when title or language is set.
.hz-code-block-titlechild elementThe filename/label text.
.hz-code-block-langchild elementThe non-interactive language tag; present only when language is set.
.hz-code-block-clipchild elementThe code region — the collapsible viewport, focusable when it renders the default code node.
.hz-code-block-gutterchild elementThe aria-hidden, non-selectable line-number column; present only with lineNumbers.
.hz-code-block-copyon a ButtonRides through Button’s class prop, so it also carries .hz-button and its data-attrs.
.hz-code-block-expandon a ButtonThe Show-more/less toggle; also a .hz-button.
code.language-<language>on the default inner codeThe class a client autoloader targets; present only when language is set and the children escape hatch is not used. Not an hz-owned class.

Accessibility

The copy button is a real labeled <button>. Its "Copied" state lasts about 2 seconds and is announced once through a polite live region. If the clipboard is denied or unavailable, nothing happens and nothing is announced, so you never get a false "copied" (WCAG 4.1.3).

In its default rendering the code region is a focusable, named role="group", so you can scroll an overflowing listing with the arrow keys (WCAG 2.1.1). When children supplies pre-highlighted markup, the region gives up its own tab stop to your focusable <pre> (Shiki's carries tabindex="0") rather than creating a second one.

The language tag is plain visible text with no interactive role. It is never the region's accessible name, so nothing is announced twice. The line-number gutter is aria-hidden and left out of selection, so a screen-reader user and a mouse copy both get clean source.

If you supply a highlighter's markup through children, its token colors (a Shiki theme, say) are yours to check for contrast. CodeBlock adds no color to that markup.

References: APG: Disclosure Pattern · MDN: Clipboard API