
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Lightweight Tailwind CSS v4 extension — pipe notation, shortcuts, visible: animations, and more
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.
p-4|8 or p-4|8|12 for mobile/tablet/desktop in one classp-4:8 as alias for pipe notationp-10px, mt-2rem, w-50% without bracket syntaxtext-sm@m instead of m:text-sm (breakpoint after class)btn-primary expands to multiple classesvisible:opacity-100onload:opacity-100 adds class after 100msbody.dark class: dark:bg-gray-900<body class="dark-auto">min-480:flex / max-320:hidden based on element width (ResizeObserver)init({ body: true }) adds mobile/tablet/desktop to <body><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.
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
const PostWind = require('postwind');
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 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>
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>
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>
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 modeAdd .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: prefixAdds 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>
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>
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 animationsIntersectionObserver-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>
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
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.
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)
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:
requestAnimationFrame)document.styleSheets<style id="postwind-main"> or <style id="postwind-shortcuts">A MutationObserver automatically processes dynamically added elements.
Requires @tailwindcss/browser v4+ and any modern browser.
MIT
FAQs
Lightweight Tailwind CSS v4 extension — pipe notation, shortcuts, visible: animations, and more
We found that postwind demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.