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

prettier-plugin-tv-groups

v0.0.2

Published

Prettier plugin: group tailwind-variants tv() base classes by modifier buckets

Readme

prettier-plugin-tv-groups

Prettier 3 plugin for tailwind-variants: it reorders the base field of tv({ ... }) (and other names you configure) into one string per modifier group (plain utilities, hover:, dark:, responsive prefixes, aria-, data-, etc.). The order of groups follows a fixed list inside the plugin; within each string, classes keep a stable order so a tool like prettier-plugin-tailwindcss can sort them afterward.

Example

Before — dozens of classes in arbitrary order, all in one base string (typical copy-paste / merge mess):

const button = tv({
  base: "dark:hover:bg-slate-800 aria-busy:pointer-events-none md:flex data-[state=open]:animate-in focus-visible:ring-2 lg:inline-flex hover:bg-primary/90 border-transparent disabled:opacity-50 dark:text-white shrink-0 active:scale-95 px-4 py-2 rounded-full size-10 border-2 focus-visible:outline-none shadow-sm text-sm font-medium transition-colors disabled:pointer-events-none dark:bg-slate-900 focus-visible:ring-offset-2",
  variants: {},
});

After Prettier runs with this plugin — base becomes an array of strings: plain layout/typography together, then hover:, focus-visible:, active:, disabled:, aria-, data-, breakpoints (md:, lg:), dark:, in a fixed group order decided by the plugin:

const button = tv({
  base: [
    "border-transparent shrink-0 px-4 py-2 rounded-full size-10 border-2 shadow-sm text-sm font-medium transition-colors",
    "hover:bg-primary/90",
    "focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-offset-2",
    "active:scale-95",
    "disabled:opacity-50 disabled:pointer-events-none",
    "aria-busy:pointer-events-none",
    "data-[state=open]:animate-in",
    "md:flex lg:inline-flex",
    "dark:hover:bg-slate-800 dark:text-white dark:bg-slate-900",
  ],
  variants: {},
});

You can see at a glance which bucket a class belongs to; diffs stay localized to one array element when you tweak e.g. only dark mode. If you also use prettier-plugin-tailwindcss, it can sort names inside each string in the same format pass. A base that stays one literal is unchanged until you format with this plugin.

Requirements

  • Node.js >= 18
  • Prettier 3.8.1 (see peerDependencies in this package)

Install

npm add -D prettier-plugin-tv-groups

Pin Prettier to the same major line your project already uses; this repo is tested with Prettier 3.8.1.
prettier-plugin-tailwindcss is an optional peer — add it when you want Tailwind class sorting in the same format run.

Which files are handled

The plugin only hooks Prettier’s typescript and babel-ts parsers. In practice that is mainly .ts / .tsx, and .jsx when Prettier uses babel-ts. Plain .js often uses the babel parser; this package does not wrap that parser, so tv() grouping may not run unless you force a compatible parser (for example via overrides in your Prettier config).

Configure Prettier

Standalone (no Tailwind sorting) — .prettierrc or prettier.config with JSON:

{
  "plugins": ["prettier-plugin-tv-groups"]
}

Option: tvGroupsFunctionNames

Array of local callee names to treat like tv. Default: ["tv"].

  • Only simple calls name({ base: ... }) are handled (Identifier callee, not foo.tv()).
  • If you use a single alias and no tv, set e.g. ["createVariants"] — then tv is not transformed unless you include it in the array.
  • [] disables grouping for this plugin.

Example:

{
  "plugins": ["prettier-plugin-tv-groups"],
  "tvGroupsFunctionNames": ["tv", "createVariants"]
}

With prettier-plugin-tailwindcss

prettier-plugin-tailwindcss is expected to be the last plugin in plugins. If you list prettier-plugin-tv-groups as a separate entry, Prettier may end up never running this plugin’s parsers, or you break Tailwind’s “last plugin” rule — so the supported approach is to attach tv-groups onto the Tailwind plugin.

Use a JavaScript config (for example prettier.config.mjs) and import attachTvGroupsToTailwind from the subpath prettier-plugin-tv-groups/attach-to-tailwind. Pass the namespace import of Tailwind’s plugin (import * as tailwindPlugin from "prettier-plugin-tailwindcss"), not a default export.

import * as tailwindPlugin from "prettier-plugin-tailwindcss";
import { attachTvGroupsToTailwind } from "prettier-plugin-tv-groups/attach-to-tailwind";

export default {
  plugins: [attachTvGroupsToTailwind(tailwindPlugin)],
  tailwindFunctions: ["tv"],
};

Add every name from tvGroupsFunctionNames to tailwindFunctions if you want class sorting inside those calls too.

If you use @ianvs/prettier-plugin-sort-imports, keep it before the combined Tailwind + tv-groups entry so import sorting still runs first.

The default export (prettier-plugin-tv-groups alone) is still useful for tests or when Tailwind is not loaded; it tries to delegate to Tailwind’s typescript / babel-ts parsers when that package is installed, but with both plugins listed separately, ordering is fragile — prefer attachTvGroupsToTailwind for day-to-day projects.

What gets rewritten

  • First argument to the call must be an object literal with a base property.
  • base may be a string literal or an array of string literals only (no template literals with ${}, spreads, or arbitrary expressions).

Renamed imports are not inferred: you must add the local name via tvGroupsFunctionNames.

Development

npm test
npm run lint

License

Licensed under the MIT License.