Components
Code block
Syntax-highlighted source with a copy button, file tabs, and package-manager tabs that remember the reader's choice. Every snippet in these docs uses it.
import { initComponents } from "htmx-ui";
// Wire up components inside content htmx inserts
document.addEventListener("htmx:after:process", (e) => {
initComponents((e.target as ParentNode) ?? document);
});
Syntax highlighting#
Code is highlighted at build time by Shiki, so pages
ship coloured HTML and no highlighting JavaScript. Supported languages: html,
css, ts/js, json, bash,
toml, md, xml/svg and jinja
(Nunjucks). Anything else is shown escaped, uncoloured.
Colours are CSS variables, --code-token-keyword, --code-token-string and so on,
defined for light and dark next to the other tokens. Override them to
restyle every code block.
:root {
--code-token-keyword: var(--color-fuchsia-600);
--code-token-string: var(--color-teal-700);
}
Package-manager commands#
Install commands come in bun, npm, pnpm and yarn flavours. Switch tabs here and every command
block on every page follows. The choice is saved in localStorage and restored on your
next visit.
bun add htmx-ui htmx.org
bun add -d tailwindcss
npm install htmx-ui htmx.org
npm install -D tailwindcss
pnpm add htmx-ui htmx.org
pnpm add -D tailwindcss
yarn add htmx-ui htmx.org
yarn add -D tailwindcss
With the Nunjucks macro, write each line with an action and it's translated for each manager:
{% from "components/code/code.html" import cli %}
{{ cli("add htmx-ui htmx.org add-dev tailwindcss run dev") }}
| Action | Description |
|---|---|
init | npm init -y · pnpm init · yarn init -y · bun init -y |
install | npm install · pnpm install · yarn install · bun install |
add | npm install · pnpm add · yarn add · bun add |
add-dev | npm install -D · pnpm add -D · yarn add -D · bun add -d |
run | npm run · pnpm run · yarn run · bun run |
exec | npx · pnpm dlx · yarn dlx · bunx |
create | npm create · pnpm create · yarn create · bun create |
anything else | Shown unchanged on every tab, e.g. mkdir my-app && cd my-app |
The commands live in htmx-ui/components/code/package-managers.json; add a manager or change the default there.
File tabs#
Show related files side by side:
<button class="btn btn-primary" hx-post="/save">Save</button>
@layer components {
.btn { @apply font-semibold; }
}
Markup#
The copy button is an icon-only clipboard button with
data-clipboard-target="pre:not([hidden]) code": the clipboard copies the nearest match, which is the
visible <code> in its own block, and shows a green tick for two seconds. .code-copy
mutes it until hovered; without a header it floats over the top-right corner of the code.
initComponents(document);
<div class="code-block" data-code>
<div class="code-block-header">
<span class="font-mono">app.ts</span>
<button type="button" class="btn btn-ghost btn-xs btn-icon clipboard code-copy" data-clipboard data-clipboard-target="pre:not([hidden]) code" aria-label="Copy code">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
</div>
<pre><code>initComponents(document);</code></pre>
</div>
For tabs, put data-tabs on the block (plus data-tabs-sync="key" to sync),
.tabs-trigger buttons with data-tab in a .tabs-list.tabs-line.code-tabs strip in the
header (underlined tabs, fitted to it), and one
<pre data-tab-panel> per tab. See Tabs.
Nunjucks macros#
{% from "components/code/code.html" import code, code_block, code_tabs, cli %}
{% call code("html", title="index.html") %}
<button class="btn btn-primary">Save</button>
{% endcall %}
{{ code_block(some_string, "ts") }}
{{ code_tabs([{ id: "a", label: "a.ts", lang: "ts", source: a }], sync="files") }}
Bodies are de-indented and escaped. Wrap Nunjucks syntax in {% raw %} so it's shown, not run.
Reference#
| Class | Description |
|---|---|
.code-block | Container: border, code background and the <pre> inside. |
.code-block-header | Top bar for a file name, tabs and the copy button. |
.code-copy | On the copy button (an icon-only .clipboard): muted until hovered. |
.code-tabs | On a .tabs-list.tabs-line of .tabs-trigger buttons: the tab strip, fitted to the header. |
data-clipboard-target="pre:not([hidden]) code" | On the copy button: copies the visible <code> of its block. |
--code-background / --code-foreground / --code-token-* | Highlighting colours (CSS variables). |