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-tailwind-align

v0.1.0

Published

Prettier plugin that sorts Tailwind CSS classes and aligns object properties — in one pass.

Readme

prettier-plugin-tailwind-align

One Prettier plugin. Two formatters. Zero conflicts.

Sorts Tailwind CSS utility classes and vertically aligns object properties — in a single pass.

npm version npm downloads license node


Table of Contents


Why this exists

Prettier only allows one plugin to own a given parser hook (e.g. parsers["typescript"]). When prettier-plugin-tailwindcss and @huggingface/prettier-plugin-vertical-align are both listed in "plugins", whichever comes last silently wins the hook — breaking the other one with no error or warning.

The common workaround is a two-pass setup: run Tailwind sorting in one Prettier pass, alignment in another. This is fragile, slow, and ties your CI to a specific script order.

prettier-plugin-tailwind-align eliminates the problem entirely. It composes both behaviours internally so Prettier sees exactly one plugin, runs one pass, and both Tailwind class sorting and object alignment happen in the correct order — guaranteed.


Installation

# npm
npm install --save-dev prettier-plugin-tailwind-align

# pnpm
pnpm add -D prettier-plugin-tailwind-align

# yarn
yarn add -D prettier-plugin-tailwind-align

# bun
bun add --dev prettier-plugin-tailwind-align

Peer dependenciesprettier and prettier-plugin-tailwindcss must be installed separately (they are not bundled).

npm install --save-dev prettier prettier-plugin-tailwindcss

Quick start

Add the plugin to your .prettierrc (or prettier.config.js / prettier.config.ts):

{
  "plugins": ["prettier-plugin-tailwind-align"],
  "tailwindStylesheet": "./app/globals.css",
  "alignInGroups": "always"
}

That's it. Remove any separate prettier-plugin-tailwindcss or @huggingface/prettier-plugin-vertical-align entries — this plugin replaces both.


Options

All options from prettier-plugin-tailwindcss are fully supported and passed through unchanged — tailwindConfig, tailwindStylesheet, tailwindFunctions, tailwindAttributes, and so on.

In addition, the following option is provided:

alignInGroups

Controls how alignment groups are computed inside object literals, interfaces, type literals, and class bodies.

| Value | Default | Description | |---|---|---| | "never" | ✅ | Every alignable property in the same block shares one alignment column. | | "always" | | A blank line starts a new independent group. Each group aligns to its own column. |

"never" — whole-block alignment

All properties align to the longest key in the entire block.

const palette = {
  red:       "#ef4444",
  green:     "#22c55e",
  blue:      "#3b82f6",
  darkGreen: "#166534",
};

"always" — group-level alignment

A blank line starts a new independent alignment group.

const palette = {
  red:   "#ef4444",
  green: "#22c55e",
  blue:  "#3b82f6",

  darkRed:   "#991b1b",
  darkGreen: "#166534",
  darkBlue:  "#1e3a8a",
};

What gets aligned

| Node type | Aligned | |---|---| | Object literal properties — { key: value } | ✅ | | TypeScript interface members | ✅ | | TypeScript type literal members | ✅ | | Class property definitions | ✅ | | Shorthand properties — { x, y, z } | ❌ skipped | | Method shorthands — { foo() {} } | ❌ skipped | | Multi-line values (key and value on different lines) | ❌ skipped | | Multiple properties sharing the same line | ❌ skipped |


Full example

Input

const config = {
  host: "localhost",
  port: 3000,
  databaseName: "mydb",
  ssl: false,
};

const theme = {
  primary: "#3b82f6",
  secondary: "#6366f1",
  background: "#ffffff",
  text: "#111827",
  border: "#e5e7eb",
};

interface User {
  id: number;
  name: string;
  email: string;
  createdAt: Date;
  isAdmin: boolean;
}

type Dimensions = {
  width: number;
  height: number;
  depth: number;
};

const palette = {
  red: "#ef4444",
  green: "#22c55e",
  blue: "#3b82f6",

  darkRed: "#991b1b",
  darkGreen: "#166534",
  darkBlue: "#1e3a8a",
};

export function Card({ title, body }: { title: string; body: string }) {
  return (
    <div className="p-4 text-sm font-medium bg-white rounded-lg shadow-md flex items-center gap-2">
      <h2 className="text-xl leading-tight font-bold text-gray-900">{title}</h2>
      <p className="mt-2 text-base text-gray-600 leading-relaxed">{body}</p>
    </div>
  );
}

const buttonVariants = {
  base: "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-2 focus:ring-blue-500",
  secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-2 focus:ring-gray-400",
  danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-2 focus:ring-red-500",
};

class ApiClient {
  baseUrl: string = "https://api.example.com";
  timeout: number = 5000;
  retries: number = 3;
  apiKey: string = "";
}

Output — with alignInGroups: "always"

const config = {
  host:         "localhost",
  port:         3000,
  databaseName: "mydb",
  ssl:          false,
};

const theme = {
  primary:    "#3b82f6",
  secondary:  "#6366f1",
  background: "#ffffff",
  text:       "#111827",
  border:     "#e5e7eb",
};

interface User {
  id:        number;
  name:      string;
  email:     string;
  createdAt: Date;
  isAdmin:   boolean;
}

type Dimensions = {
  width:  number;
  height: number;
  depth:  number;
};

const palette = {
  red:   "#ef4444",
  green: "#22c55e",   // group 1 — aligns to "green:" width
  blue:  "#3b82f6",

  darkRed:   "#991b1b",
  darkGreen: "#166534",  // group 2 — aligns to "darkGreen:" width independently
  darkBlue:  "#1e3a8a",
};

// Tailwind classes sorted, object values aligned — in one pass
export function Card({ title, body }: { title: string; body: string }) {
  return (
    <div className="flex items-center gap-2 rounded-lg bg-white p-4 text-sm font-medium shadow-md">
      <h2 className="text-xl leading-tight font-bold text-gray-900">{title}</h2>
      <p className="mt-2 text-base leading-relaxed text-gray-600">{body}</p>
    </div>
  );
}

const buttonVariants = {
  base:      "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  primary:   "bg-blue-600 text-white hover:bg-blue-700 focus:ring-2 focus:ring-blue-500",
  secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-2 focus:ring-gray-400",
  danger:    "bg-red-600 text-white hover:bg-red-700 focus:ring-2 focus:ring-red-500",
};

class ApiClient {
  baseUrl: string = "https://api.example.com";
  timeout: number = 5000;
  retries: number = 3;
  apiKey:  string = "";
}

Migrating from two separate plugins

Before:

{
  "plugins": [
    "prettier-plugin-tailwindcss",
    "@huggingface/prettier-plugin-vertical-align"
  ],
  "tailwindStylesheet": "./app/globals.css",
  "alignInGroups": "always"
}

After:

{
  "plugins": ["prettier-plugin-tailwind-align"],
  "tailwindStylesheet": "./app/globals.css",
  "alignInGroups": "always"
}

Then uninstall the old plugins:

npm uninstall prettier-plugin-tailwindcss @huggingface/prettier-plugin-vertical-align

The alignInGroups option name is kept identical to @huggingface/prettier-plugin-vertical-align's option, so existing configs work without any value changes.


Local development

git clone https://github.com/w3Scribe/prettier-plugin-tailwind-align.git
cd prettier-plugin-tailwind-align
bun install

bun run build       # compile src/ → dist/
bun run dev         # watch mode
bun run typecheck   # type-check without emitting
bun run test        # run the test suite

Compatibility

| | Version | |---|---| | prettier | ^3.0 | | prettier-plugin-tailwindcss | ^0.7 | | Node.js | >=18 |


License

MIT © Sudhir Gadpayle