Server shell + client leaf

Code Block

A compound multi-line code container with header, copy button and editor chrome.

App.tsx
import { AstralisProvider } from "astralis-ui";
import "astralis-ui/styles.css";

export function App({ children }) {
  return <AstralisProvider>{children}</AstralisProvider>;
}

Import#

import { CodeBlock } from "astralis-ui";
// CodeBlock.Root, .Header, .Title, .Control, .CopyTrigger,
// .WindowControls, .Content, .Code

Anatomy#

Root holds the source string via code and hands it to its parts during server render: Code renders it when given no children, and CopyTrigger, the compound's only client part, copies the rendered code to the clipboard. Header is an optional top row for Title, WindowControls (the macOS traffic lights) and a trailing Control slot; Content is the scrollable <pre> wrapping Code.

<CodeBlock.Root variant="solid" code={source}>
  <CodeBlock.Header>
    <CodeBlock.WindowControls />
    <CodeBlock.Title>App.tsx</CodeBlock.Title>
    <CodeBlock.Control>
      <CodeBlock.CopyTrigger />
    </CodeBlock.Control>
  </CodeBlock.Header>
  <CodeBlock.Content>
    <CodeBlock.Code />
  </CodeBlock.Content>
</CodeBlock.Root>

Variants#

The same three-variant family as Code; solid is the strongest surface: it tracks the active theme (dark block in dark mode, light in light) and pairs well with WindowControls.

pnpm add astralis-ui  # subtle
pnpm add astralis-ui  # outline
pnpm add astralis-ui  # solid

Syntax highlighting#

Code Block renders plain text by itself: bring your own highlighter and pass its output as highlightedHtml on Code. The blocks on this very site are Shiki output rendered this way:

import { codeToHtml } from "shiki";

const html = await codeToHtml(source, { lang: "tsx", theme: "github-dark" });

<CodeBlock.Root variant="solid" code={source}>
  <CodeBlock.Content>
    <CodeBlock.Code highlightedHtml={html} />
  </CodeBlock.Content>
</CodeBlock.Root>

Keep passing the raw string as code on Root so CopyTrigger copies the unhighlighted source.

Props#

CodeBlock.Root:

PropTypeDefaultDescription
variant"subtle" | "solid" | "outline""subtle"Container style. Every variant follows the active light or dark theme.
size"sm" | "md" | "lg""md"Font size and padding of the content.
codestringNoneThe source. Code renders it when given no children, and CopyTrigger copies it.

Parts#

Every part also takes its element's native attributes and className.

PropTypeDefaultDescription
CodeBlock.Headerdiv propsNoneOptional top row for Title, WindowControls and a trailing Control slot.
CodeBlock.Titlespan propsNoneFile name or caption in the header.
CodeBlock.WindowControlsspan propsNoneThree decorative window dots, hidden from assistive technology.
CodeBlock.Controldiv propsNoneTrailing header slot, usually holding the CopyTrigger.
CodeBlock.CopyTriggercode?: string · children?: ReactNode | ((copied: boolean) => ReactNode)NoneCopies the Root's code, or its own code override. A render function replaces the default copy and check glyphs.
CodeBlock.Contentpre propsNoneThe scrollable pre element that wraps Code.
CodeBlock.CodehighlightedHtml?: stringNoneRenders the Root's code as plain text, or your highlighter's HTML when highlightedHtml is set.