Skip to content
cennge-ui
GitHubv0.3.1, changelog

Snippet

A command with a copy button. The $ in front is shown, never copied.

  1. Install
    pnpm add cennge-ui
  2. Work on the library
    git clone https://github.com/Cennge/cennge-uicd cennge-uipnpm installpnpm dev
  3. End-to-end tests on desktop
    pnpm exec playwright test --project=chromium --project=firefox --project=webkit
  1. Press a copy button: a check mark shows for two seconds and screen readers hear "Copied".
  2. A string with line breaks gets a $ on every line; the button copies all the lines, without the $.
  3. A command wider than its box scrolls sideways. It then takes focus with Tab, and the arrow keys scroll it.
Live: copy a command, or Tab to the long one and scroll it with the arrow keys.

Field marks

Import
import { Snippet } from "cennge-ui";
Size
2.6 KB gzip for this import, its dependencies aside
Pattern
A <pre> and a native <button> that the code describes
Keyboard
Enter SpaceArrow left Arrow right
SSR
Rendered on the server in the Next.js check; hydrates without a warning
Clipboard
The Clipboard API; a selected textarea where it is missing, as on plain http
Tests
Unit tests; end-to-end in Chromium, Firefox and WebKit, on desktop and phone viewports: snippet

When to use#

Use a Snippet for a command or a short line the reader will paste somewhere else: an install command, a clone URL, a few setup steps. For longer code with highlighting, a code block in Prose or your own highlighter reads better.

Similar#

  • Kbd shows keys to press, not text to paste.
  • Button runs an action. A Snippet keeps the command as text you can select and puts its own button beside it.

Copy something other than what is shown#

codeString is copied instead of the visible text, so the snippet can show a short form and copy the full one. symbol={false} drops the $ for text that is not a shell command. onCopy gets the copied text; here it is shown in a toast.

github.com/Cennge/payload-cache
clone-url.tsx
import { Snippet, toast } from "cennge-ui";

export default function CloneUrl() {
  return (
    <Snippet
      symbol={false}
      codeString="https://github.com/Cennge/payload-cache.git"
      onCopy={(text) => toast("Clone URL copied", { description: text })}
      className="w-full max-w-80"
    >
      github.com/Cennge/payload-cache
    </Snippet>
  );
}

Variants, colours and sizes#

Four variants in seven colours; every variant has the same height, so snippets line up in a row. Of the three sizes, md is the default, and a one-line snippet at that size is as tall as an Input. symbol takes any prompt, such as > for Windows.

pnpm test
pnpm size
pnpm build
pnpm release
pnpm dev
pnpm test:e2e
rmdir /s /q dist
variants.tsx
import { Snippet } from "cennge-ui";

export default function SnippetVariants() {
  return (
    <div className="flex flex-col gap-4">
      <div className="flex flex-wrap items-center gap-3">
        <Snippet>pnpm test</Snippet>
        <Snippet variant="faded">pnpm size</Snippet>
        <Snippet variant="bordered" color="primary">
          pnpm build
        </Snippet>
        <Snippet variant="solid" color="primary">
          pnpm release
        </Snippet>
      </div>
      <div className="flex flex-wrap items-center gap-3">
        <Snippet size="sm" color="success">
          pnpm dev
        </Snippet>
        <Snippet size="lg" radius="full" color="success">
          pnpm test:e2e
        </Snippet>
        <Snippet color="danger" symbol=">">
          rmdir /s /q dist
        </Snippet>
      </div>
    </div>
  );
}

Copying on plain http#

Browsers offer the Clipboard API only on https and localhost. Opened over plain http, for example a dev server on another device, Snippet copies through a hidden textarea instead. It puts the textarea next to the button and returns focus there afterwards, so copying works inside a Dialog too. If both ways fail, no check mark appears and onCopy is not called.

Accessibility#

The copy button is named "Copy" and described by the code beside it (aria-describedby), so a screen reader says what will be copied. The symbol is aria-hidden. After copying, "Copied" is announced through a polite live region. copyLabel and copiedLabel translate both words. Pressing Enter or Space on the button copies and leaves focus on it.

Styling#

classNames reaches the parts: base (the box), pre (the scrolling code), symbol and copyButton. className goes on the box, as base does.

Props#

PropTypeDefault
children
React.ReactNodeThe command. A string with line breaks shows one row per line, each with its own symbol.
–
symbol
React.ReactNodeShown before every line; never copied or read out. false hides it.
"$"
codeString
stringCopied instead of the visible text.
–
onCopy
(text: string) => voidCalled with the copied text.
–
timeout
numberHow long the check mark stays after copying, ms.
2000
hideCopyButton
boolean
–
copyLabel
stringAccessible name of the copy button.
"Copy"
copiedLabel
stringAnnounced to screen readers after copying.
"Copied"
variant
"bordered""flat""faded""solid"
"flat"
color
"default""primary""secondary""success""warning""danger""info"
"default"
size
"sm""md""lg"
"md"
radius
"none""sm""md""lg""full"
"md"
classNames
Partial<Record<SnippetSlots, string>>
–

Also takes every attribute of <div>, except color, children, onCopy, which mean something else here.