Skip to content

Modifiers

Modifiers wrap a StyleRule with a pseudo-class selector or media query. Use them as tw chain properties or with when().

// tw chain syntax
tw.hover(tw.bg('blue-600'))
tw.md.p(8)
tw.hover(tw.bg('blue-600').textColor('white'))
// when() syntax
cx(when(hover)(bg('blue-600')))
cx(when(hover, md)(bg('blue-700'))) // stacked: hover inside md

ModifierSelectorCommon use
hover:hoverButton/link color changes
focus:focusInput focus states
active:activeButton press effect
disabled:disabledDisabled form controls
focusVisible:focus-visibleKeyboard-only focus rings
focusWithin:focus-withinParent highlight on child focus
firstChild:first-childRemove top margin/border on first item
lastChild:last-childRemove bottom margin/border on last item
// tw syntax
tw.bg.blue500
.hover(tw.bg.blue600)
.active(tw.bg.blue700)
.focusVisible(tw.ring('2px', '#3b82f6'))
.disabled(tw.opacity(0.5))
// cx syntax
cx(
bg.blue500,
when(hover)(bg.blue600),
when(disabled)(opacity(0.5), cursor.notAllowed),
when(focusVisible)(ring('2px', '#3b82f6')),
)

Mobile-first min-width approach:

ModifierBreakpointMedia query
sm640px@media (min-width: 640px)
md768px@media (min-width: 768px)
lg1024px@media (min-width: 1024px)
xl1280px@media (min-width: 1280px)
_2xl1536px@media (min-width: 1536px)

Desktop-first max-width approach:

ModifierBreakpointMedia query
maxSm640px@media (max-width: 639px)
maxMd768px@media (max-width: 767px)
maxLg1024px@media (max-width: 1023px)
maxXl1280px@media (max-width: 1279px)
max2xl1536px@media (max-width: 1535px)
// tw syntax -- progressive enhancement
tw.flexCol.gap(4).p(4)
.sm(tw.gap(6))
.md(tw.flexRow)
.lg(tw.p(8))
// cx syntax
cx(
flexCol(), gap(4), p(4),
when(sm)(gap(6)),
when(md)(flexRow()),
when(lg)(p(8)),
)
tw.grid(1).gap(4)
.sm(tw.grid(2))
.md(tw.grid(3).gap(6))
.lg(tw.grid(4).gap(8))

ModifierMedia query
dark@media (prefers-color-scheme: dark)

Responds to the user’s system preference. For manual theme toggling, use the Theme API.

tw.bg.white.textColor.gray900
.dark(tw.bg.slate900.textColor.slate100)
// With hover in dark mode (cx syntax):
cx(
when(hover)(bg.gray100),
when(dark, hover)(bg.slate700),
)

Pass multiple modifiers to when() — they apply right-to-left:

when(hover, md)(bg('blue-700'))
// @media (min-width: 768px) { .cls:hover { background-color: ... } }
when(dark, md)(bg('slate-800'))
// @media (min-width: 768px) { @media (prefers-color-scheme: dark) { ... } }

Since Modifier is (rule: StyleRule) => StyleRule, you can create your own:

import { wrapWithSelector, wrapWithMediaQuery } from 'typewritingclass/rule'
const checked: Modifier = (rule) => wrapWithSelector(rule, ':checked')
const print: Modifier = (rule) => wrapWithMediaQuery(rule, 'print')
const reducedMotion: Modifier = (rule) =>
wrapWithMediaQuery(rule, '(prefers-reduced-motion: reduce)')

Custom modifiers compose with when() and all built-in modifiers. See Writing Modifiers for full details.