Code Block
Block-level source display with optional syntax highlighting and explicit wrapping.
Contract
| Axis | Values | Default |
|---|---|---|
language | any grammar the configured highlighter supports | plain text |
| Highlighter | highlighter prop, TRCodeHighlighterProvider, none | none |
| Syntax theme | chosen by the highlighter; the Tinyrack docs highlighter follows the active Tinyrack theme | github-light-high-contrast, github-dark-high-contrast |
wrap | true, false | false |
Install
pnpm add @tinyrack/uiScroll inside the code area to read long lines.
Styles
@import '@tinyrack/ui/components/code-block.css';Scroll inside the code area to read long lines.
Imports
import { TRCodeBlock } from '@tinyrack/ui/components/code-block';Scroll inside the code area to read long lines.
Playground
Usage
The highlighted examples use trShikiWebHighlighter. Add Shiki before copying them:
pnpm add shiki
Examples
Additional languages permalink
Use the language identifier that matches the source. An identifier the highlighter does not support renders as plain text rather than failing.
Copy action with visible result permalink
Copy is an application action, so compose it with TRButton and a live result instead of hiding clipboard state inside TRCodeBlock.
The composed copy example additionally needs these application-action imports:
import { useState } from 'react';
import { TRButton } from '@tinyrack/ui/components/button';
import '@tinyrack/ui/components/button.css';
API
TRCodeBlock ships no grammars. Supply a highlighter through the highlighter prop or TRCodeHighlighterProvider, and the set of valid language values follows from that choice. See Syntax highlighting for the setup paths.
Highlighting happens after hydration; the original source remains SSR-safe and visible until the highlighter resolves. Changing code or language cancels stale work so an earlier async result can never replace the current source.
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | required | Source text rendered inside semantic <pre><code> markup. |
language | string | undefined | Grammar identifier passed to the highlighter; omit it for plain text. |
highlighter | TRCodeHighlighter | provider value | Overrides the highlighter from context for this block. |
onHighlightFailure | (failure: TRCodeHighlightFailure) => void | provider value | Receives unsupported-language, highlight-failed, and no-highlighter outcomes. |
wrap | boolean | false | Wraps long lines instead of exposing horizontal overflow. |
ref | Ref<HTMLPreElement> | — | References the native pre element. |
className, style | native pre props | — | Applies consumer classes, inline styles, and component-token overrides. |
The block reports its state on data-highlight: plain without a language, pending while the highlighter runs, highlighted on success, unsupported when the highlighter has no grammar, no-highlighter when none is configured, and error when the highlighter throws. Every outcome other than success keeps the SSR fallback visible, so failures degrade to readable plain text rather than an empty block. Without an onHighlightFailure handler, only error reaches the console, once per language. A missing highlighter and an unsupported language are configuration states whose correct rendering is plain text, so they stay quiet and surface through data-highlight alone.
All other native pre attributes and events are forwarded. Add an aria-label when surrounding prose does not already identify the source. Highlighting never changes the accessible source text.
Styles
| Token | Purpose |
|---|---|
--tr-code-block-background | Surface, including highlighted blocks |
--tr-code-block-border | Border color |
--tr-code-block-border-width | Border width |
--tr-code-block-color | Fallback source color |
--tr-code-block-font-family | Monospace family |
--tr-code-block-font-size | Source size |
--tr-code-block-line-height | Source leading |
--tr-code-block-padding-x | Inline padding |
--tr-code-block-padding-y | Block padding |
--tr-code-block-radius | Corner radius |
With wrap={false}, the block contains long lines with horizontal overflow. With wrap, long tokens break inside the available width. Both modes stay bounded by their parent.