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

postwind

v0.6.1

Published

Lightweight Tailwind CSS v4 extension — pipe notation, shortcuts, visible: animations, and more

Readme

PostWind

PostWind is a lightweight runtime extension for Tailwind CSS v4 browser runtime. It adds pipe notation, shortcuts, scroll animations, dark mode, container queries, and more — all in a single ~500-line file. Every standard Tailwind class works unchanged.

Features unique to PostWind

  • Pipe responsivep-4|8 or p-4|8|12 for mobile/tablet/desktop in one class
  • Colon responsivep-4:8 as alias for pipe notation
  • Unit suffixesp-10px, mt-2rem, w-50% without bracket syntax
  • @ notationtext-sm@m instead of m:text-sm (breakpoint after class)
  • Shortcuts — composable class aliases: btn-primary expands to multiple classes
  • visible: — IntersectionObserver scroll animations: visible:opacity-100
  • onload: — entrance animations: onload:opacity-100 adds class after 100ms
  • dark: — dark mode via body.dark class: dark:bg-gray-900
  • dark-auto — auto-detect OS dark mode on <body class="dark-auto">
  • Container queriesmin-480:flex / max-320:hidden based on element width (ResizeObserver)
  • Body breakpoint classinit({ body: true }) adds mobile/tablet/desktop to <body>
  • m: t: d: prefixes — short breakpoint aliases for mobile/tablet/desktop

Setup

CDN / script tag

<script src="https://cdn.jsdelivr.net/npm/postwind@latest/src/postwind.js"></script>
<script>
  PostWind.init({
    tailwind: true,
    shortcuts: {
      'btn': 'px-4 py-2 rounded font-medium cursor-pointer transition-colors',
      'btn-primary': 'btn bg-blue-600 text-white hover:bg-blue-500',
    }
  });
</script>

Loads the IIFE directly — sets window.PostWind, no bundler needed. Pass tailwind: true to auto-load the Tailwind CSS v4 browser runtime from CDN.

npm (ESM)

import PostWind from 'postwind'; // auto-loads Tailwind CDN

PostWind.init({
  shortcuts: { ... }
});

The default import auto-injects the Tailwind CDN script. If you already load Tailwind yourself, use the lib-only import:

import PostWind from 'postwind/lib'; // no Tailwind CDN injection

npm (CJS)

const PostWind = require('postwind');

Features

Pipe notation (responsive)

Compact responsive values. 2 values = mobile|tablet, 3 values = mobile|tablet|desktop.

<div class="p-4|8">padding: 16px mobile, 32px tablet+</div>
<div class="text-sm|base|2xl">3-breakpoint font size</div>

Colon responsive notation

Colon as an alias for pipe:

<div class="p-4:8">same as p-4|8</div>
<div class="p-4:8:12">same as p-4|8|12</div>

Breakpoint prefixes

Short aliases: m: = mobile (max-width: 767px), t: = tablet (min-width: 768px), d: = desktop (min-width: 1024px).

<div class="m:text-sm d:text-2xl">Small on mobile, large on desktop</div>

Unit suffix shorthand

Write p-10px instead of p-[10px]. Supports px, rem, em, vh, vw, %, and more.

<div class="p-10px mt-2rem w-50%">clean arbitrary values</div>

Shortcuts

Composable class aliases defined at runtime. Can nest other shortcuts.

PostWind.init({
  shortcuts: {
    'btn': 'px-4 py-2 rounded font-medium cursor-pointer transition-colors',
    'btn-primary': 'btn bg-blue-600 text-white hover:bg-blue-500',
    'btn-danger': 'btn bg-red-600 text-white hover:bg-red-500',
    'card': 'bg-white rounded-2xl border p-6 shadow-md',
  }
});
<button class="btn-primary">Click me</button>
<div class="card">Card content</div>

Shortcut CSS goes into <style id="postwind-shortcuts">, everything else into <style id="postwind-main">.

dark: dark mode

Add .dark to <body> to activate all dark: prefixed classes. PostWind generates body.dark .dark\:class selectors.

<body class="dark">
  <div class="bg-white dark:bg-gray-900 text-black dark:text-white">
    adapts to dark mode
  </div>
</body>

Toggle via JS:

document.body.classList.toggle('dark');

dark-auto (auto-detect OS preference)

Add dark-auto to <body> to automatically detect OS dark mode preference and listen for changes.

<body class="dark-auto">
  <!-- automatically adds .dark class based on OS prefers-color-scheme -->
</body>

@ notation (property-first breakpoints)

Write the breakpoint suffix after the class with @. text-sm@m becomes m:text-sm.

<div class="text-sm@m text-2xl@d">small on mobile, large on desktop</div>
<div class="flex@d hidden@m">desktop flex, mobile hidden</div>

onload: prefix

Adds a class 100ms after page load. Useful for entrance animations.

<div class="opacity-0 transition duration-500 onload:opacity-100">
  fades in on page load
</div>

Container queries (min-/max- width)

Element-width container queries using ResizeObserver. Toggles inner classes based on the element's own width (not viewport).

<div class="min-480:flex">becomes flex when this element is >= 480px wide</div>
<div class="max-320:hidden">hidden when this element is <= 320px wide</div>

Body breakpoint class

Adds mobile, tablet, or desktop class to <body> based on viewport width. Opt-in via init({ body: true }).

PostWind.init({ body: true });
<!-- body gets class="mobile" (<768px), "tablet" (768-1023px), or "desktop" (>=1024px) -->
<style>
  body.mobile .sidebar { display: none; }
</style>

visible: scroll animations

IntersectionObserver-based. Classes activate when element is 50% visible in the viewport.

<div class="opacity-0 translate-y-8 transition duration-700 visible:opacity-100 visible:translate-y-0">
  slides up and fades in when scrolled into view
</div>

API

PostWind.init(options)            // initialize (tailwind, shortcuts, breakpoints, body)
PostWind.shortcut(name, classes)  // register a shortcut
PostWind.breakpoint(name, media)  // register a breakpoint
PostWind.resolve(className)       // resolve a class to CSS (Promise)
PostWind.twCSS(className)         // get Tailwind CSS for a class (Promise)
PostWind.ready()                  // Promise that resolves when Tailwind is ready
PostWind(className)               // inject CSS for a class (Promise)
PostWind.cache                    // object of cached class promises
PostWind.observeVisible(el)       // manually observe element for visible: classes
PostWind.processElement(el)       // manually process all PostWind classes on an element

Development

bun run dev      # start dev server (port 8000) + watch/rebuild dist
bun run start    # start dev server only
bun run build    # production build (dist/)
bun run test     # run tests via Playwright
bun run publish  # bump patch version, build, test, publish to npm

Tests are defined in example/index.html as inline browser tests. bun test launches Playwright, loads the demo page, and reads the results — single source of truth, no duplication.

Project structure

src/postwind.js    # entire library (~500 lines, browser IIFE)
src/bundle.js      # ESM entry — auto-loads Tailwind CDN
src/lib.js         # ESM entry — no Tailwind CDN
src/postwind.test.js  # Playwright test runner
example/index.html # demo page + inline tests
bin/server.js      # dev server
dist/              # built output (ESM, CJS, minified)

How it works

PostWind runs in the browser alongside @tailwindcss/browser. When it encounters a PostWind class (pipe notation, shortcut, breakpoint prefix, unit suffix, visible:, dark:, onload:, @ notation, or container query), it:

  1. Creates a temporary DOM element with the equivalent Tailwind class
  2. Waits for Tailwind to generate CSS (via requestAnimationFrame)
  3. Reads the CSS from document.styleSheets
  4. Re-wraps it with the PostWind selector and media queries
  5. Appends to <style id="postwind-main"> or <style id="postwind-shortcuts">

A MutationObserver automatically processes dynamically added elements.

Browser support

Requires @tailwindcss/browser v4+ and any modern browser.

License

MIT