Package Manager Tabs

Ox Content can expand a single <pm> block into an accessible tab group with one tab per package manager — npm, pnpm, yarn, bun, and vp (Vite+), in that order. You write the command once using npm syntax and the renderer converts it to each package manager's equivalent natively (in Rust, with no client-side JavaScript required for the tabs themselves).

Authoring package-manager tabs

Package-manager tabs are opt-in. Enable them before authoring <pm> blocks:

import { oxContent } from "@ox-content/vite-plugin";

export default {
  plugins: [
    oxContent({
      embeds: {
        pm: true,
      },
    }),
  ],
};

Write a <pm> element containing a single npm-style command:

<pm>npm install -D vite</pm>

The renderer expands it into the same tab widget used by <tabs>, so styling and keyboard navigation are consistent. See examples/builtin-features/content/tabs.md for the compact tab source. Each tab body is a code block with the command converted for that package manager.

Rendered example

npm install -D vite
pnpm add -D vite
yarn add -D vite
bun add -D vite
vp install -D vite

Conversion rules

The command is written using npm syntax and converted to the others:

npm pnpm yarn bun vp
npm install pnpm install yarn bun install vp install
npm install <pkg> pnpm add <pkg> yarn add <pkg> bun add <pkg> vp install <pkg>
npm i <pkg> pnpm add <pkg> yarn add <pkg> bun add <pkg> vp install <pkg>
npm install -D <pkg> pnpm add -D yarn add -D bun add -D vp install -D
npm install -g <pkg> pnpm add -g yarn global add bun add -g vp install -g
npm uninstall <pkg> pnpm remove yarn remove bun remove vp uninstall
npm run <script> pnpm run yarn <script> bun run vp run
npx <bin> pnpm dlx <bin> yarn dlx <bin> bunx <bin> vp exec -- <bin>

Package versions, scopes (@scope/pkg), additional flags, and multiple packages are preserved. Both -D/--save-dev and -g/--global are recognized.

Synced tab groups (opt-in)

By default each package-manager tab group is independent and works with no JavaScript. You can opt in to syncing so that selecting (for example) pnpm in one block selects pnpm in every other package-manager block on the page, with the choice persisted in localStorage.

Enable it through the embeds.pm option:

import { oxContent } from "@ox-content/vite-plugin";

export default {
  plugins: [
    oxContent({
      // Synced tab groups are OFF by default.
      embeds: {
        pm: { sync: true },
      },
    }),
  ],
};

When syncing is enabled, the group element gains a data-ox-tab-group="pkg-manager" attribute and a tiny dependency-free runtime keeps the groups in sync. When syncing is disabled (the default) the attribute is not emitted and the widget behaves exactly like a standalone tab group.

Notes

  • The tab widget itself requires no client-side JavaScript; selection uses CSS :has(), with a <details> fallback for readers without CSS or JS.
  • Syncing is the only behavior that uses JavaScript, and it is opt-in.
  • Unrecognized commands are passed through unchanged, so authoring never breaks silently.