Installation
No package manager needed. Download chai.js and drop one script tag at the end of your body. That's the entire setup.
<!-- add at the very end of body --> <script src="chai.js"></script>
<head>, the DOM won't be ready and nothing will be styled.
document.querySelectorAll('[style]').length — should return a number greater than 0.
How it works
chai.js runs once on DOMContentLoaded. It walks every element, parses chai-* class names, resolves them against a rules map, and injects inline styles.
// 1. inject keyframes for animate-* utilities injectKeyframes() // 2. walk every element document.querySelectorAll('*').forEach(el => { el.classList.forEach(cls => { if (!cls.startsWith('chai-')) return // 3. parse: chai-p-4 → prop: 'p', val: '4' const { prop, val } = parseClass(cls) // 4. look up rules map and apply const styles = rules[prop](val) Object.assign(el.style, styles) // 5. clean up the class el.classList.remove(cls) }) })
Quick start
A complete working example — a card built entirely with chai-* classes.
<div class="chai-bg-white chai-rounded-xl chai-shadow-lg chai-p-6 chai-w-full"> <h2 class="chai-text-xl chai-font-bold chai-mb-2">Hello ChaiTailwind</h2> <p class="chai-text-sm chai-text-gray chai-mb-4"> Utility-first CSS at runtime. </p> <button class="chai-bg-blue chai-text-white chai-px-4 chai-py-2 chai-rounded-lg chai-cursor-pointer chai-transition chai-hover-bg-indigo"> Get started </button> </div> <script src="chai.js"></script>
Hello ChaiTailwind
Utility-first CSS at runtime.
Spacing
All spacing utilities use a 4px scale — chai-p-4 = padding: 16px. Supports 0–16 and beyond.
| Class | CSS output |
|---|---|
| chai-p-{n} | padding: n×4px |
| chai-px-{n} | padding-left: n×4px; padding-right: n×4px |
| chai-py-{n} | padding-top: n×4px; padding-bottom: n×4px |
| chai-pt/pb/pl/pr-{n} | padding-top / bottom / left / right: n×4px |
| chai-m-{n} | margin: n×4px |
| chai-mx-{n} | margin-left: n×4px; margin-right: n×4px |
| chai-mx-auto | margin-left: auto; margin-right: auto |
| chai-my-{n} | margin-top: n×4px; margin-bottom: n×4px |
| chai-mt/mb/ml/mr-{n} | margin-top / bottom / left / right: n×4px |
| chai-gap-{n} | gap: n×4px |
| chai-gap-x-{n} | column-gap: n×4px |
| chai-gap-y-{n} | row-gap: n×4px |
Colors
Apply background and text colors using named colors or custom hex values.
| Class | CSS output |
|---|---|
| chai-bg-{color} | background-color: {value} |
| chai-text-{color} | color: {value} |
| chai-bg-[#hexcode] | background-color: #hexcode |
| chai-text-[#hexcode] | color: #hexcode |
| chai-bg-[var(--x)] | background-color: var(--x) |
Named colors: red · blue · green · yellow · orange · purple · pink · gray · white · black · slate · teal · cyan · indigo · lime · amber · rose
Typography
| Class | CSS output |
|---|---|
| chai-text-xs | font-size: 12px |
| chai-text-sm | font-size: 14px |
| chai-text-base | font-size: 16px |
| chai-text-lg | font-size: 18px |
| chai-text-xl | font-size: 20px |
| chai-text-2xl/3xl/4xl | font-size: 24px / 30px / 36px |
| chai-font-bold | font-weight: bold |
| chai-font-semibold | font-weight: 600 |
| chai-font-normal | font-weight: normal |
| chai-font-italic | font-style: italic |
| chai-text-center/left/right | text-align: center / left / right |
| chai-uppercase/lowercase/capitalize | text-transform |
| chai-underline | text-decoration: underline |
| chai-truncate | overflow: hidden; text-overflow: ellipsis; white-space: nowrap |
| chai-line-clamp-{n} | -webkit-line-clamp: n |
| chai-tracking-tight/wide/wider | letter-spacing |
| chai-leading-tight/normal/relaxed/loose | line-height |
Borders
| Class | CSS output |
|---|---|
| chai-border | border: 1px solid #d1d5db |
| chai-border-t/b/l/r | border-top / bottom / left / right |
| chai-border-2 / border-4 | border: 2px / 4px solid #d1d5db |
| chai-border-none | border: none |
| chai-rounded-sm | border-radius: 3px |
| chai-rounded | border-radius: 6px |
| chai-rounded-md/lg/xl/2xl | border-radius: 8px / 12px / 16px / 20px |
| chai-rounded-full | border-radius: 9999px |
| chai-outline-none | outline: none |
| chai-ring | box-shadow: 0 0 0 3px rgba(59,130,246,0.5) |
Layout
| Class | CSS output |
|---|---|
| chai-flex | display: flex |
| chai-block / chai-inline / chai-hidden | display: block / inline / none |
| chai-inline-flex / chai-inline-block | display: inline-flex / inline-block |
| chai-grid | display: grid |
| chai-grid-cols-{n} | grid-template-columns: repeat(n, 1fr) |
| chai-flex-col / chai-flex-row | flex-direction: column / row |
| chai-flex-wrap / chai-flex-nowrap | flex-wrap: wrap / nowrap |
| chai-flex-1 / chai-flex-auto / chai-flex-none | flex shorthand |
| chai-items-center/start/end/stretch | align-items |
| chai-justify-center/between/around/end | justify-content |
| chai-relative / chai-absolute / chai-fixed / chai-sticky | position |
| chai-z-{n} | z-index: n |
| chai-inset-0 | top/right/bottom/left: 0 |
Hover states new
Since inline styles can't use :hover, chai.js attaches mouseenter/mouseleave event listeners instead. Prefix any utility with hover-.
<button class="chai-bg-black chai-text-white chai-hover-bg-blue chai-transition chai-px-6 chai-py-3 chai-rounded-lg"> Hover me </button>
chai-transition for smooth color changes on hover.Group hover new
Mark a parent with chai-group. Any child with chai-group-hover-* will react when the parent is hovered.
<div class="chai-group chai-p-6 chai-bg-white chai-rounded-xl chai-cursor-pointer"> <div class="chai-group-hover-bg-blue chai-rounded-full"> icon </div> <h3 class="chai-group-hover-text-blue"> Title </h3> </div>
Responsive new
Prefix any utility with a breakpoint to apply it only above that width. Recalculates on window resize.
| Prefix | Breakpoint | Example |
|---|---|---|
| chai-sm-* | ≥ 640px | chai-sm-p-4 |
| chai-md-* | ≥ 768px | chai-md-bg-blue |
| chai-lg-* | ≥ 1024px | chai-lg-text-xl |
| chai-xl-* | ≥ 1280px | chai-xl-hidden |
<!-- red on mobile, blue at sm, green at md --> <div class="chai-bg-red chai-sm-bg-blue chai-md-bg-green"> Responsive background </div>
Dark mode new
Prefix any utility with dark- to apply it only when the system is in dark mode. Reads prefers-color-scheme: dark on load.
<div class="chai-bg-white chai-text-black chai-dark-bg-black chai-dark-text-white chai-p-6 chai-rounded-xl"> Adapts to system theme </div>
Animations new
Keyframes are injected once into <head> by chai.js on load. No separate CSS file needed.
| Class | Effect |
|---|---|
| chai-animate-spin | continuous 360° rotation |
| chai-animate-ping | scale + fade out (like a radar ping) |
| chai-animate-pulse | opacity fade in/out |
| chai-animate-bounce | vertical bounce |
| chai-animate-fade-in | fade in from opacity 0 |
| chai-animate-slide-up | slide up + fade in |
| chai-animate-none | removes animation |
Transitions new
| Class | CSS output |
|---|---|
| chai-transition | transition: all 0.2s ease |
| chai-transition-colors | transition: color, background-color, border-color 0.2s |
| chai-transition-transform | transition: transform 0.2s ease |
| chai-duration-150/200/300/500 | transition-duration: 150ms / 200ms / 300ms / 500ms |
| chai-ease-in/out/in-out | transition-timing-function |
Custom colors
Use square brackets to pass any hex code or CSS variable directly.
<!-- hex codes --> <div class="chai-bg-[#ff6347] chai-text-[#ffffff]">Tomato</div> <!-- CSS variables --> <div class="chai-bg-[var(--brand-color)]">Brand color</div>
Search utilities
Find any utility by class name or CSS property.