Custom rules
A rule is a function that takes (token, theme) and returns either a style object or null. The library exposes three ways to register one — all three end up appended to a list of “custom rules” that’s tried before the built-ins.
Function form (most general)
chai.extend((token, theme) => { if (token === 'spin') { return { animation: 'spin 1s linear infinite' }; } return null;});<div class="chai-spin">…</div>The returned object uses camelCase property names; the engine kebab-cases them at write time.
Static-rule form
For exact-match utilities, this is more compact:
chai.extend({ test: 'spin', style: { animation: 'spin 1s linear infinite' }});Pattern-rule form
For families of utilities driven by a regex:
chai.extend({ pattern: /^rotate-(\d+)$/, build: (m) => ({ transform: `rotate(${m[1]}deg)` })});<div class="chai-rotate-45">…</div><div class="chai-rotate-90">…</div>Theme-aware rules
Rules receive the merged theme as the second argument, so you can read scales from it:
chai.extend({ pattern: /^elevation-(\d+)$/, build: (m, theme) => ({ boxShadow: theme.shadow[m[1]] || `0 ${m[1]}px ${m[1] * 2}px rgba(0,0,0,0.1)` })});Order matters
Rules are stored in registration order. Within the merged list (custom rules first, then built-ins), the first match wins. If you want to override a built-in utility, register your rule before the built-in runs:
const chai = new Chai({ rules: [ // overrides chai-text-center to also apply text-align: justify (token) => token === 'text-center' ? { textAlign: 'center', textJustify: 'inter-word' } : null ]});Bulk registration
Pass rules: [...] to the constructor to register many at once. This is the recommended pattern when the rule set is part of your design system.
new Chai({ rules: [ { pattern: /^rotate-(-?\d+)$/, build: (m) => ({ transform: `rotate(${m[1]}deg)` }) }, { pattern: /^scale-(\d+)$/, build: (m) => ({ transform: `scale(${m[1] / 100})` }) }, { test: 'no-tap', style: { WebkitTapHighlightColor: 'transparent' } } ]});Keeping it tidy
For anything beyond a handful of rules, give them a home of their own:
export const transformRules = [ { pattern: /^rotate-(-?\d+)$/, build: (m) => ({ transform: `rotate(${m[1]}deg)` }) }, { pattern: /^scale-(\d+)$/, build: (m) => ({ transform: `scale(${m[1] / 100})` }) }];
// main.jsimport { Chai } from 'chaitailwind';import { transformRules } from './theme/extras.js';
new Chai({ rules: transformRules });Made by Saad · @developedbysaad on X