npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

comark-tabs

v0.11.0

Published

Tabs and code groups for Markdown, with keys and labels synced across the page. They read without a script. A Comark plugin.

Readme

comark-tabs

npm version npm downloads license docs

Tabs and code groups, written in Markdown. Without a script every tab shows under its label, one after another; the script adds the tab strip, the arrow keys, and sync, which switches every block with the same key at once and remembers the choice. A Comark plugin for HTML, Vue, React, and Svelte.

pnpm add comark comark-tabs
import { createHtmlRenderer } from "@comark/html";
import tabs, { components } from "comark-tabs/html";

const render = createHtmlRenderer({ plugins: [tabs()], components });

Each :::tabs-item inside ::tabs is a tab. In a ::code-group, each code block is one, labelled by the name in brackets after its language:

::tabs{sync="os"}
:::tabs-item{label="macOS"}
Press **⌘K** to find the pigeon data.
:::

:::tabs-item{label="Windows"}
Press **Ctrl+K** to find the pigeon data.
:::
::

::code-group{sync="pm"}
```sh [pnpm]
pnpm add comark-tabs
```

```sh [npm]
npm install comark-tabs
```
::

A code block marked pm after its language, as in sh pm, holds package manager commands in any manager, npm, pnpm, yarn, bun, or deno, and becomes a code group with sync="pm" and a tab each for npm, pnpm, yarn, and bun. It reads installs, adds, removes, updates, scripts, npx and dlx, create, and init, and only commands that start a line or follow &&, ||, or ; change. Choose the managers and their order with tabs({ managers: ["pnpm", "npm", "yarn", "bun", "deno"] }).

A tab takes an icon, an Iconify name or an image URL: :::tabs-item{label="macOS" icon="lucide:apple"}, or icon=logos:pnpm after a code block's label. comark-icon resolves it while parsing, from the Iconify API by default, and draws it as a CSS image, in the text's color when it has one color. Pass the resolver your :icons use as tabs({ iconResolver }), and icons by label for every block as tabs({ icons: { pnpm: "logos:pnpm" } }). Size them with --comark-icon-size.

The markup follows the WAI-ARIA tabs pattern: ←, →, Home, and End move between tabs and open them. Blocks with the same sync switch together by label, the choice is saved in localStorage under comark-tabs: and the key, and the page scrolls to keep the clicked tab still when blocks above it change height. Labels and sync can be bound to the front matter, such as :label="frontmatter.name".

The plugin adds every problem to meta.issues, so a host can reject a document before publishing it: a tab without a label, two tabs with the same label, a pm command a package manager has no form for (its tab is left out), a pm block with no command, an icon it can't find or load, content outside every tab (it doesn't render), anything but code blocks in a code group, a block with no tabs, and a :::tabs-item outside ::tabs (it renders as plain content). Each issue names its block and says how to fix it.

Renderers

| Renderer | Import | | --- | --- | | @comark/html | comark-tabs/html: the script is inlined | | @comark/vue | comark-tabs/vue | | @comark/react | comark-tabs/react | | @comark/svelte | comark-tabs/svelte, Svelte 5.20 or later |

Each entry exports the parse plugin as default and the renderer's components.

The tab strip is a segmented control in the style of shadcn/ui, and in a code group it's the header of one card with the code block. The styles read shadcn's CSS variables, such as --background and --border, when the page has them, and use its neutral theme otherwise. Set the --comark-* tokens to theme every comark plugin at once. The rules sit in a comark CSS layer, so any plain rule of your own wins, except the one that joins a code group's block to its header. --ct-surface, --ct-active, --ct-active-text, --ct-gap, and --ct-font-size change the strip, the open tab, and the labels; see the tabs' Theming page.

A code group moves the tokens two snippets share when you switch tabs, if they share at least half of them. Write ::code-group{magic} to always animate or ::code-group{magic="false"} to never animate. Keyboard navigation and reduced motion switch at once, and it works with sync and comark-code.