Skip to content

Chainable API with tw

tw is a proxy-based chainable style builder. One import gives you access to every utility, modifier, and value-less shorthand.

import { tw } from 'typewritingclass'
const card = tw
.p(6)
.bg.white
.rounded.xl
.shadow.md

Design tokens (colors, radius, shadows, typography, layout enums) are accessed as properties — no strings needed:

tw.bg.blue500 // background-color: #3b82f6
tw.textColor.slate900 // color: #0f172a
tw.rounded.lg // border-radius: 0.5rem
tw.shadow.md // box-shadow
tw.text.lg // font-size + line-height
tw.font.bold // font-weight: 700
tw.items.center // align-items: center
tw.justify.between // justify-content: space-between
tw.cursor.pointer // cursor: pointer

Color tokens support opacity via callable syntax:

tw.bg.blue500(50) // background-color: rgb(59 130 246 / 0.5)
tw.bg.blue500(25) // 25% opacity

Spacing, sizing, and arbitrary CSS values use function calls:

tw.p(4).gap(8).w('100%').h(12)
tw.opacity(0.5).z(10).border(1)

Accessed as properties instead of function calls:

tw.flex.flexCol.gap(4)
tw.relative.overflow.hidden
tw.italic.truncate.antialiased
tw.group
.bg.white
.rounded.lg
.p(4)

Pass any CSS value as a string argument — useful for one-off values:

tw.bg('#ff6347').rounded('0.625rem')
tw.shadow('0 4px 12px rgba(0,0,0,0.15)')

Single-utility modifiers (property syntax)

Section titled “Single-utility modifiers (property syntax)”

The modifier applies to the next utility in the chain:

tw.bg.white.hover(tw.bg('blue-50')).focus(tw.ring(2))
tw.p(4).md.p(8).lg.p(12)
tw.bg.white.dark(tw.bg.slate900)
tw.opacity(0.5).groupHover(tw.opacity(1))

When a modifier should apply to multiple styles, call it as a function:

tw.hover(
tw.bg.blue500
.textColor.white
.shadow.lg
)
const card = tw
.p(6)
.bg.white
.rounded.xl
.hover(tw.bg.slate100.shadow.lg.scale(105))
.focus(tw.ring(2).ringColor.blue500)

The compiler replaces tw chains with class name strings at build time, so they work directly in any context:

// React
<div className={tw.p(4).bg.blue500} />
// Vanilla JS
element.className = tw.p(4).bg.blue500
// Template literals
const classes = `${tw.p(4)} extra-class`

Every access returns a new chain:

const base = tw.flex.flexCol
const a = base.gap(4) // flex + flexCol + gap(4)
const b = base.gap(8) // flex + flexCol + gap(8)
// base is unchanged

Both APIs produce identical CSS. Choose based on preference:

cx + whentw
ImportsMany individual importsSingle tw import
Modifierswhen(hover)(bg.blue600)tw.hover(tw.bg.blue600)
Value-lesscx(flex(), flexCol())tw.flex.flexCol
Tokenscx(bg.blue500, rounded.lg)tw.bg.blue500.rounded.lg
Dynamic valuesdcx(bg(dynamic(color)))Use cx/dcx for dynamic values