A lightweight layer on top of Tailwind CSS browser runtime. Adds responsive shorthands, unit suffixes, shortcuts, and scroll-triggered animations.
PostWind is a ~3KB JavaScript library that extends Tailwind CSS with convenience features for prototyping and static pages. It runs in the browser alongside @tailwindcss/browser@4.
It does not replace Tailwind. Standard Tailwind classes work as-is. PostWind adds:
p-4|8 or p-4|8|12 for mobile / tablet / desktopp-4:8 as alias for p-4|8p-10px, mt-2rem, w-50% without bracket syntaxtext-sm@m instead of m:text-sm (breakpoint after class)btn-primary expands to multiple classesbody.dark classbody.dark-automin-480:flex / max-320:hidden based on element widthinit({ body: true }) adds mobile/tablet/desktop to <body>1. Tailwind generates CSS. PostWind uses Tailwind's browser runtime as its CSS engine. When PostWind needs to know what p-4 produces, it creates a temporary DOM element with that class, waits for Tailwind to process it, then extracts the CSS rules from the generated stylesheet.
2. PostWind re-wraps the CSS. It takes the extracted CSS properties and wraps them in new selectors and media queries. For example, p-4|8 extracts both p-4 and p-8 CSS, then generates:
3. Injected into the page. Generated rules go into <style id="postwind-main"> and <style id="postwind-shortcuts"> elements. A cache prevents duplicate injection.
4. Auto-scan. On DOMContentLoaded, PostWind scans all elements for PostWind-specific classes (pipes, unit suffixes, colon responsive, visible:) and injects their CSS automatically. A MutationObserver watches for dynamically added elements.
PostWind.init({ tailwind: true }) loads Tailwind from CDN. Without tailwind: true, PostWind works as a class processor only (Tailwind must be loaded separately). Returns a Promise.
Full JavaScript API for PostWind.
PostWind.init(options?)
returns Promise
Initializes PostWind. Pass tailwind: true to load Tailwind CSS browser runtime from CDN (default: false). Returns a Promise that resolves when ready.
PostWind(className)
returns Promise<string|null>
Resolves the CSS for a PostWind class and injects it into the page. Returns the generated CSS string or null. Cached — calling twice with the same class only injects once.
PostWind.ready()
returns Promise
Returns a Promise that resolves when Tailwind is loaded and ready. Same promise as init() returns.
PostWind.resolve(className)
returns Promise<string|null>
Like PostWind() but returns the CSS string without injecting it. Useful for debugging or building custom tooling.
PostWind.twCSS(className)
returns Promise<string|null>
Extracts raw CSS properties from Tailwind for a single class. Creates a temp element, waits for Tailwind to process, returns the CSS text (e.g. padding: 1rem;).
PostWind.shortcut(name, classes)
Register a shortcut: a single class name that expands to multiple Tailwind classes. Supports nesting — reference other shortcuts by name. Can be called anytime (in init or after).
PostWind.breakpoint(name, mediaQuery)
Register or override a named breakpoint. Used by prefix notation (m:, t:, d:) and pipe notation. Can be called anytime.
Defaults: m = max-width:767px, t = min-width:768px, d = min-width:1024px
PostWind.observeVisible(element)
Manually observe an element with the IntersectionObserver. Adds pw-visible class when 50% visible. Usually not needed — auto-scan handles elements with visible: classes.
| Syntax | Example | Equivalent Tailwind |
|---|---|---|
| Pipe (2-seg) | p-4|8 | p-4 md:p-8 |
| Pipe (3-seg) | p-4|8|12 | p-4 md:p-8 lg:p-12 |
| Colon (2-seg) | p-4:8 | p-4 md:p-8 |
| Colon (3-seg) | p-4:8:12 | p-4 md:p-8 lg:p-12 |
| Unit suffix | p-10px | p-[10px] |
| Mobile prefix | m:hidden | max-width:767px |
| Tablet prefix | t:flex | md:flex |
| Desktop prefix | d:flex | lg:flex |
| Visible | visible:opacity-100 | IntersectionObserver |
| Dark mode | dark:bg-gray-900 | body.dark scoped |
| @ notation | text-sm@m | m:text-sm |
| Onload | onload:opacity-100 | class added after 100ms |
| Container min | min-480:flex | ResizeObserver |
| Container max | max-320:hidden | ResizeObserver |
| Shortcut | btn-primary | user-defined |
Standard Tailwind classes work as-is. PostWind doesn't change anything — these are just Tailwind.
flex gap-4 items-center
flex justify-between items-center
flex flex-col md:flex-row gap-4
flex flex-wrap gap-2
flex items-stretch gap-4 (equal height)
flex items-center justify-center h-32 (centering)
grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4
grid grid-cols-3 gap-4 (auto-fit with span)
text-5xl font-bold tracking-tight
Heading 5XL
text-3xl font-semibold
Heading 3XL
text-xl font-medium text-gray-700
Subheading XL
text-base leading-relaxed text-gray-600
Body text with relaxed leading. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
text-sm text-gray-500 italic
Small italic caption text
text-xs uppercase tracking-widest font-semibold text-gray-400
Overline label
line-clamp-2 (truncate to 2 lines)
This paragraph is truncated to exactly two lines using line-clamp-2. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.
bg-{color}-{shade} — Full Tailwind color palette
bg-gradient-to-r from-{color} to-{color}
p-{n} m-{n} gap-{n} space-y-{n}
p-4 sm:p-6 md:p-8 lg:p-12 xl:p-16
rounded-{size}
shadow-{size}
border border-{color} ring-{n}
w-full sm:w-3/4 md:w-1/2 lg:w-1/3 (responsive)
relative + absolute positioning
truncate
This is a very long text that will be truncated with an ellipsis because it overflows its container width
overflow-auto max-h-24
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
opacity-{n}
aspect-{ratio}
Mobile-first like Tailwind. Pipe is mobile|tablet or mobile|tablet|desktop. Left is base, rest override at breakpoints.
Mobile padding vs tablet+ padding
p-4|12 = p-4 (base) + t:p-12 (768px+)
Resize window to see text change
text-xl|4xl = text-xl (base) + t:text-4xl (768px+)
grid-cols-1|3 = 1 col (base) + t:3 cols (768px+)
m: = max-width:767px | t: = min-width:768px | d: = min-width:1024px
gap-2|8 = gap-2 (base) + t:gap-8 (768px+)
Multiple pipe classes on one element
p-4|10 text-lg|2xl rounded-xl|3xl
Three breakpoints in one class
p-3|6|12 text-base|xl|4xl grid-cols-1|2|4
grid-cols-1|2|4 = 1 col (mobile) + 2 cols (tablet 768px+) + 4 cols (desktop 1024px+)
Write p-10px instead of p-[10px]. Auto-detected and injected.
p-10px p-20px p-40px
mt-1rem mt-2rem
w-200px w-50% w-30vw max-w-500px
text-14px (= text-[14px])
text-18px (= text-[18px])
text-24px (= text-[24px])
text-1.5rem (= text-[1.5rem])
text-14px text-18px text-24px text-1.5rem
gap-15px rounded-8px
Use p-4:8 as an alias for p-4|8. Same mobile-first logic.
Padding and text change at tablet
p-4:10 text-lg:2xl = p-4|10 text-lg|2xl
Three breakpoints via colons
p-3:6:12 text-base:xl:3xl = p-3|6|12 text-base|xl|3xl
grid-cols-1:2:4 = 1 col (mobile) + 2 cols (768px+) + 4 cols (1024px+)
Unit suffixes work inside pipe/colon notation too
p-10px:20px:40px text-14px:18px:24px
Compose multiple Tailwind classes into a single reusable class name.
btn-xs btn px-2 py-1 text-xs roundedbtn-sm btn px-3 py-1.5 text-xs rounded-mdbtn inline-flex items-center justify-center px-4 py-2 rounded-lg font-medium transition-all duration-200 cursor-pointer text-smbtn-lg btn px-6 py-3 text-base rounded-xlbtn-primary btn bg-blue-600 text-white hover:bg-blue-500 active:bg-blue-700btn-secondary btn bg-gray-200 text-gray-800 hover:bg-gray-300 active:bg-gray-400btn-danger btn bg-red-600 text-white hover:bg-red-500 active:bg-red-700btn-success btn bg-emerald-600 text-white hover:bg-emerald-500 active:bg-emerald-700btn-warning btn bg-amber-500 text-white hover:bg-amber-400 active:bg-amber-600btn-info btn bg-sky-500 text-white hover:bg-sky-400 active:bg-sky-600btn-dark btn bg-gray-900 text-white hover:bg-gray-800 active:bg-gray-950btn-light btn bg-white text-gray-800 hover:bg-gray-50 active:bg-gray-100 border border-gray-200btn-outline btn bg-transparent border-2 border-gray-300 text-gray-700 hover:bg-gray-100btn-outline-primary btn bg-transparent border-2 border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-whitebtn-outline-danger btn bg-transparent border-2 border-red-600 text-red-600 hover:bg-red-600 hover:text-whitebtn-outline-success btn bg-transparent border-2 border-emerald-600 text-emerald-600 hover:bg-emerald-600 hover:text-whitebtn-ghost btn bg-transparent text-gray-600 hover:bg-gray-100btn-link btn bg-transparent text-blue-600 hover:underlinebtn-pill btn rounded-fullbtn-pill-primary btn rounded-full bg-blue-600 text-white hover:bg-blue-500btn-pill-danger btn rounded-full bg-red-600 text-white hover:bg-red-500btn-gradient btn bg-gradient-to-r from-blue-600 to-purple-600 text-white hover:from-blue-500 hover:to-purple-500btn-gradient-warm btn bg-gradient-to-r from-orange-500 to-pink-500 text-white hover:from-orange-400 hover:to-pink-400btn-gradient-cool btn bg-gradient-to-r from-cyan-500 to-blue-500 text-white hover:from-cyan-400 hover:to-blue-400btn-shadow btn bg-white text-gray-800 border border-gray-200 shadow-sm hover:shadow-lg hover:-translate-y-0.5btn-shadow-primary btn bg-blue-600 text-white shadow-md shadow-blue-500/30 hover:shadow-xl hover:shadow-blue-500/40 hover:-translate-y-0.5btn-shadow-danger btn bg-red-600 text-white shadow-md shadow-red-500/30 hover:shadow-xl hover:shadow-red-500/40 hover:-translate-y-0.5btn-shadow-success btn bg-emerald-600 text-white shadow-md shadow-emerald-500/30 hover:shadow-xl hover:shadow-emerald-500/40 hover:-translate-y-0.5btn-icon btn p-2 rounded-lgbtn-icon-round btn p-2 rounded-fullbadge-primary badge-success badge-danger badge-warning
Using the card shortcut class.
card = bg-white rounded-xl border border-gray-200 p-6
Elements animate when they scroll into view (50% threshold). Scroll down to see them appear.
Property-first alternative to breakpoint prefixes. Put the breakpoint at the end with @.
Adds a class 100ms after page load. Perfect for entrance animations.
Per-element responsive rules using ResizeObserver. Based on the element's own width, not the viewport.
Toggle .dark on <body> to activate dark: prefixed classes.
.dark from body
This card adapts its background, text, and border colors when dark mode is active.
Same result, different syntax.
px-4 md:px-8
px-4|8
px-4 md:px-6 lg:px-8
px-4|6|8
grid-cols-1 md:grid-cols-2 lg:grid-cols-4
grid-cols-1|2|4
text-xl md:text-3xl lg:text-5xl
text-xl|3xl|5xl
hidden md:block
m:hidden t:block
flex flex-col md:flex-row
flex m:flex-col t:flex-row
Testing PostWind breakpoints, pipes, shortcuts, visible: prefix, and dark: mode.