Code
CodeGroup, PackageManager, Snippet, FileTree, Kbd — the components for code, files, and keys.
~ 1 min read
| Component | Use for |
|---|---|
<CodeGroup> | Tab multiple code blocks; auto-syncs on known label families |
<PackageManager> | npm/yarn/pnpm/bun installs and scripts |
<Snippet> | Reuse content across pages |
<FileTree> | Render a directory tree from a Markdown list |
<Kbd> | Keyboard chord, with auto Cmd→Ctrl on non-Mac |
CodeGroup
Wraps two or more code blocks and renders them as tabs. Each child’s data-filename (from the title="..." fence attribute) or language hint becomes the tab label.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Sync key. Same name on multiple blocks → matched tabs across the page and across navigations (persisted in localStorage). When empty, the runtime auto-derives a name if the labels match a known family (npm/yarn/pnpm/bun, pip/uv/poetry, macOS/Linux/Windows, python/typescript, …). |
Multiple languages
<CodeGroup>
```ts title="fetch.ts"
await fetch("https://api.example.com/v1/users")
```
```py title="fetch.py"
requests.get("https://api.example.com/v1/users")
```
```sh title="curl"
curl https://api.example.com/v1/users
```
</CodeGroup>await fetch("https://api.example.com/v1/users")requests.get("https://api.example.com/v1/users")curl https://api.example.com/v1/usersSynced across blocks
Pick TypeScript on the first block — the second block flips to TypeScript too.
<CodeGroup name="lang">
```ts
console.log("hello")
```
```py
print("hello")
```
</CodeGroup>
<CodeGroup name="lang">
```ts
console.log("done")
```
```py
print("done")
```
</CodeGroup>Auto-sync (no name)
When labels match a known family, sync happens automatically — pick bun once, every install block on the page flips. Works across pages too.
<CodeGroup>
```bash bun
bun add tangly
```
```bash npm
npm install tangly
```
```bash pnpm
pnpm add tangly
```
```bash yarn
yarn add tangly
```
</CodeGroup>Recognized families: auto:pkg-js, auto:pkg-py, auto:pkg-rust, auto:os, auto:shell, auto:runtime-js, auto:lang, auto:editor. Full list in code-sync.ts.
Tab label resolution
Per child, in priority order:
data-filename(from code-fencetitle="...")data-language(the language token after the opening fence)"Tab N"fallback
PackageManager
<PackageManager> renders an install or run command across npm, yarn, pnpm, and bun. Tabs auto-sync as auto:pkg-js so a single pick on any install block (raw <CodeGroup> or <PackageManager>) propagates everywhere.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Package name to install. Required unless command is set. |
mode | "dev" | "prod" | "prod" | "dev" installs as devDependency. |
command | string | — | Run a script instead of installing. e.g. "run build". |
syncName | string | "" | Empty default → joins the auto:pkg-js pool. Override only to break the link. |
Install
<PackageManager name="tangly" />npm install tanglyyarn add tanglypnpm add tanglybun add tanglyInstall as dev dependency
<PackageManager name="@tanglydocs/schema" mode="dev" />npm install --save-dev @tanglydocs/schemayarn add --dev @tanglydocs/schemapnpm add --save-dev @tanglydocs/schemabun add --dev @tanglydocs/schemaRun a script
<PackageManager command="run build" />npm run buildyarn run buildpnpm run buildbun run buildIndependent block
To break sync for a specific block, give it a unique syncName:
<PackageManager name="@tanglydocs/cli" syncName="cli-only" />Snippet
Reusable inline content. Phase-1 placeholder — accepts inline children for now; the file-resolved form (file="snippets/x.mdx") lands in Phase 2.
| Prop | Type | Default | Description |
|---|---|---|---|
file | string | — | Path under snippets/. Phase-2; ignored today. |
<Snippet file="snippets/install.mdx">
Inline fallback content. Renders as-is until file resolution lands.
</Snippet>For most reuse cases today, embedded blocks cover the same need.
FileTree
Turns a nested Markdown list into a styled directory tree. Indentation drives nesting. Files pick icons from their extension. **bold** highlights a row. Trailing text becomes a comment. ... is a placeholder.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "terminal" | "ascii" | "default" | Visual style — see below |
chrome | boolean | false | Only on terminal — draws three macOS-style window dots |
Default
src
components
- Button.tsx
- Card.tsx the file you’ll edit
- Note.astro
styles
- globals.css
- …
- package.json dependencies
- tangly.config.ts
<FileTree>
- src
- components
- Button.tsx
- **Card.tsx** the file you'll edit
- Note.astro
- styles
- globals.css
- ...
- package.json dependencies
- tangly.config.ts
</FileTree>Terminal variant
Drops the icons, swaps in literal ├──/└── connectors, ships a dark background that ignores theme — like running tree in a shell. Add chrome for the macOS window header.
my-docs/
- docs.json
- introduction.mdx
guides/
- deploying.mdx
- themes.mdx
- package.json
<FileTree variant="terminal" chrome>
- my-docs/
- docs.json
- introduction.mdx
- guides/
- **deploying.mdx**
- package.json
</FileTree>ASCII variant
Minimal — no card, no background, no icons. Use when a tree sits inside another component (Card, Step, Accordion) and the boxed look would be too heavy.
packages/
theme-ui/
components/
- FileTree.astro
- rehype-file-tree.ts
docs/
- …
<FileTree variant="ascii">
- packages/
- theme-ui/
- components/
- **FileTree.astro**
- docs/
</FileTree>Authoring syntax
Five things to know:
- Directories — A line ending in
/is a directory; so is any line with nested children. Directories are collapsible (<details open>) — readers can fold them shut. - Highlighting — Wrap a row in
**bold**to highlight it. - Comments — Anything after the filename becomes a muted comment. Inline Markdown works.
- Placeholders — A row containing only
...(or…) draws a dimmed placeholder row. - Custom icons — Prefix a row with
<Icon icon="..." />to override the auto-detected file icon.
<FileTree>
- <Icon icon="cog" /> config
- <Icon icon="database" /> data
</FileTree>Kbd
Renders styled keycap(s). Either pass children for a single key, or keys="..." for a chord — + and whitespace separate keys, and Cmd / ⌘ swap to Ctrl on non-Mac platforms.
| Prop | Type | Default | Description |
|---|---|---|---|
keys | string | — | Chord string. e.g. "Cmd+K", "Shift Tab". |
Single key
Press <Kbd>Tab</Kbd> to autocomplete.Press Tab to autocomplete.
Chord (auto Cmd→Ctrl)
Open the command palette with <Kbd keys="Cmd+K" />.Open the command palette with Cmd+K.
On Linux and Windows the same chord renders as Ctrl + K.
Manual chord
<Kbd>Shift</Kbd>+<Kbd>Tab</Kbd>Shift+Tab