G · 06 guides

Guides / Utility Classes

Utility Classes

Aihu's css-engine ships a focused Tailwind-v4 utility subset compiled at build time into per-component scoped CSS. This page is the authoritative index of every supported class, every variant, every brand token, and a "Not yet supported" callout so you know when to drop to arbitrary values or open an issue.

At a glance

  • Compiled by @aihu/css-engine from .aihu SFCs.
  • Output is scoped CSS (shadow DOM by default, light DOM via shadowMode: 'light').
  • Unknown classes are silently dropped — there is no "JIT" and no global utility sheet.
  • Conflict resolution (cn()) is last-wins per property group.

Class index by family

Layout (display, position, overflow)

Class Declaration
block / inline-block / inline display: block / inline-block / inline;
flex / inline-flex display: flex / inline-flex;
grid / inline-grid display: grid / inline-grid;
hidden display: none;
static / relative / absolute / fixed / sticky position: …;
overflow-auto / -hidden / -scroll / -visible overflow: …;

Flex & Grid alignment

Class Declaration
flex-row / flex-col flex-direction: row / column;
flex-wrap / flex-nowrap flex-wrap: …;
items-start / -center / -end / -stretch align-items: …;
justify-start / -center / -between / -around / -end justify-content: …;

Grid templating

Class Declaration
grid-cols-N grid-template-columns: repeat(N, minmax(0, 1fr));
grid-cols-none grid-template-columns: none;
grid-rows-N grid-template-rows: repeat(N, minmax(0, 1fr));
grid-rows-none grid-template-rows: none;
col-span-N grid-column: span N / span N;
col-span-full grid-column: 1 / -1;
col-auto grid-column: auto;
row-span-N grid-row: span N / span N;
row-span-full grid-row: 1 / -1;
row-auto grid-row: auto;

N is any positive integer.

Spacing (padding, margin, gap, space-x/y)

Spacing uses the Tailwind scale: each unit is 0.25rem (so p-41rem), plus px1px and 00.

Class Declaration
p- / px- / py- / pt- pr-* pb-* pl-* padding…: <scale>;
m- / mx- / my- / mt- mr-* mb-* ml-* margin…: <scale>;
mx-auto / my-auto / mt-auto margin-inline / margin-block / margin-top: auto;
gap- / gap-x- / gap-y-* gap…: <scale>;
space-x-N & > * + * { margin-inline-start: <scale>; }
space-y-N & > * + * { margin-block-start: <scale>; }

space-x/y-* emit Tailwind's standard sibling-margin recipe as a nested rule (no margin on the first child; the gap lands on every following sibling).

Position scale (top/right/bottom/left/inset)

Inset utilities use the same Tailwind spacing scale as padding/margin (each unit 0.25rem, 00), plus the auto keyword. Prefix the class with - for negative offsets (-top-4top: -1rem;). inset- sets all four sides; inset-x- / inset-y-* set the logical inline / block pairs.

Class Declaration
top-N / right-N / bottom-N / left-N top / right / bottom / left: <scale>;
top-auto / right-auto top: auto; etc.
-top-N / -left-N … (negative) top: -<scale>; etc.
inset-N inset: <scale>;
inset-0 inset: 0;
inset-x-N inset-inline: <scale>;
inset-y-N inset-block: <scale>;

N is any spacing-scale step (e.g. 0, 2, 4, 0.5). Arbitrary values still work for one-offs: top-[3px], inset-[10%].

Sizing (width, height, min/max)

Class Declaration
w- / h- (scale + fractions) width / height: …;
w-full / w-screen / w-auto width: 100% / 100vw / auto;
h-full / h-screen / h-auto height: 100% / 100vh / auto;
min-w- / max-w- / min-h- / max-h- min/max sizing
max-w-{xs…7xl} named scale: 20rem … 80rem
max-w-prose max-width: 65ch;
max-w-screen-{sm…2xl} breakpoint widths (40rem … 96rem)
max-w-{none,full,min,max,fit} keyword max-widths

Named max-w-* scale: xs 20rem, sm 24rem, md 28rem, lg 32rem, xl 36rem, 2xl 42rem, 3xl 48rem, 4xl 56rem, 5xl 64rem, 6xl 72rem, 7xl 80rem.

Typography

Class Declaration
text-{xs…3xl} font-size + line-height
text-left / -center / -right text-align: …;
font-{thin…black} font-weight: …;
italic / not-italic font-style: …;
underline / line-through / no-underline text-decoration-line: …;
uppercase / lowercase / capitalize text-transform: …;
truncate ellipsis overflow recipe

Leading & tracking scale

Named line-height (leading-) and letter-spacing (tracking-) scales, matching the Tailwind v4 defaults. leading-<n> (numeric) maps to the spacing scale (leading-61.5rem); the named steps are unitless multipliers. Arbitrary values still work: leading-[1.4], tracking-[.2em].

Class Declaration
leading-none line-height: 1;
leading-tight line-height: 1.25;
leading-snug line-height: 1.375;
leading-normal line-height: 1.5;
leading-relaxed line-height: 1.625;
leading-loose line-height: 2;
leading-N line-height: <spacing-scale>;
tracking-tighter letter-spacing: -0.05em;
tracking-tight letter-spacing: -0.025em;
tracking-normal letter-spacing: 0em;
tracking-wide letter-spacing: 0.025em;
tracking-wider letter-spacing: 0.05em;
tracking-widest letter-spacing: 0.1em;

Colors (bg, text, border, fill, stroke, ring, outline)

bg-, text-, border-, fill-, stroke- accept both brand tokens (see below) and the palette (bg-red-500, text-slate-700, bg-white). Brand-token classes emit var(--color-).

Borders (width incl. directional, radius, color)

Class Declaration
border border-width: 1px;
border-{0,2,4,8} border-width: 0 / 2px / 4px / 8px;
border-x-{0,2,4,8} / border-y-{…} border-inline-width / border-block-width
border-t/r/b/l-{0,2,4,8} border-top/right/bottom/left-width
rounded / -sm / -md / -lg / -full border-radius: …;

Divide (sibling borders)

Borders between adjacent children, reusing the same nested & > * + * recipe as space-x/y. The bare form defaults to 1px.

Class Declaration
divide-x / divide-y & > * + * { border-inline-width / border-block-width: 1px; }
divide-x-{0,2,4,8} & > * + * { border-inline-width: 0 / 2px / 4px / 8px; }
divide-y-{0,2,4,8} & > * + * { border-block-width: 0 / 2px / 4px / 8px; }
divide-x-reverse / divide-y-reverse & > * + * { --tw-divide-{x,y}-reverse: 1; }

Set the border color on the same element with the standard color utilities (e.g. border-muted). The -reverse tokens keep Tailwind's API surface via the --tw-divide-{x,y}-reverse custom property.

Effects

Class Declaration
shadow / -md / -lg / -none box-shadow: …;
opacity-* opacity: …;

Ring

A focus ring drawn as a box-shadow composed from --tw-ring- custom properties (the Tailwind v4 recipe), so the ring width, color, and offset are set independently and layer with a regular shadow-.

Class Declaration
ring 3px ring (box-shadow from --tw-ring-*)
ring-{0,1,2,4,8} ring at that pixel width: --tw-ring-shadow: … calc({n}px + var(--tw-ring-offset-width)) var(--tw-ring-color);
ring-inset --tw-ring-inset: inset; (draws the ring inside the edge)
ring-offset-{0,1,2,4,8} --tw-ring-offset-width: {n}px; (gap between the element and the ring)
ring-<color> sets the ring color: --tw-ring-color: var(--color-*);

The width side (ring-{n}) and the color side (ring-<color>) are complementary — use them together, e.g. focus:ring-2 ring-blue-500. The color path is unchanged; ring-blue-500, ring-primary, ring-ring etc. still emit --tw-ring-color.

Z-index

z-0, z-10, z-20, z-30, z-40, z-50, z-autoz-index: …;.

Motion

Motion utilities cover transforms, transitions, and animations. Each transform utility (translate-, rotate-, scale-*) emits a single transform: declaration rather than composing CSS variables — so within one element the CSS cascade applies last-wins per family. To combine transforms (e.g. translate and rotate) on one element, use an arbitrary value (transform-[...] is not yet wired; compose with a custom @style rule).

transform / translate

Class Declaration
transform identity baseline (translate(0,0) rotate(0) … scaleX(1) scaleY(1))
transform-none transform: none;
translate-x-N / translate-y-N transform: translateX/Y(<spacing-scale>);
-translate-x-N / -translate-y-N negative translate (e.g. -0.5rem)

translate-* uses the spacing scale (translate-x-20.5rem). The leading - produces the negative form.

rotate / scale

Class Declaration
rotate-N transform: rotate(Ndeg);
-rotate-N transform: rotate(-Ndeg);
scale-N transform: scale(N/100); (e.g. scale-1051.05)
scale-x-N / scale-y-N transform: scaleX/Y(N/100);

transition / duration / ease

Class Declaration
transition default property set + 150ms + cubic-bezier(0.4, 0, 0.2, 1)
transition-none transition-property: none;
transition-all transition-property: all; + default timing
transition-colors color/bg/border/decoration/fill/stroke + default timing
transition-opacity transition-property: opacity; + default timing
transition-transform transition-property: transform; + default timing
duration-N transition-duration: Nms;
ease-linear transition-timing-function: linear;
ease-in / ease-out / ease-in-out cubic-bezier easing functions

animate

Class Declaration
animate-none animation: none;
animate-spin animation: spin 1s linear infinite; + @keyframes spin
animate-ping animation: ping …; + @keyframes ping
animate-pulse animation: pulse …; + @keyframes pulse
animate-bounce animation: bounce 1s infinite; + @keyframes bounce

This is only the original five — the animate- family has grown well past this list (fade/slide-in variants, flips, 90°/180°/360° rotations, zoom in/out, jelly, tada, heartbeat, blink, and more). Each animate- (except animate-none) emits its @keyframes block as a top-level sibling rule alongside the class rule — keyframes cannot be nested inside a selector body. Re-emitting an identical block is idempotent in CSS.

Variants

  • Web-Component-native: host:, slotted:, slotted-<tag>:, part-<name>:, host-context-<name>:
  • Pseudo: hover:, focus:, focus-visible:, active:, disabled:, visited:, checked:
  • Responsive (min-width): sm: 40rem, md: 48rem, lg: 64rem, xl: 80rem, 2xl: 96rem (override via @theme)
  • Dark mode: dark: (Firefox-safe [data-theme="dark"] / .dark cascade)
  • Arbitrary selectors: [&>li]:, [&:has(img)]:, etc.
  • Stacking: md:hover:bg-primary — left-to-right composition

aria-/data- attribute variants

Gate a utility on an ARIA state or a data-* attribute. The variant compiles to an attribute selector appended to the class.

Variant Selector Notes
aria-checked: [aria-checked="true"] implicit ="true"
aria-disabled: [aria-disabled="true"]
aria-expanded: [aria-expanded="true"]
aria-selected: [aria-selected="true"]
aria-pressed: [aria-pressed="true"]
aria-[expanded=false]: [aria-expanded="false"] arbitrary name=value
data-[state=open]: [data-state="open"] arbitrary name=value
data-active: [data-active] bare data-* → presence (no ="true")
governedaihuaihu247 B
aria-expanded:bg-accent      →  .aria-expanded\:bg-accent[aria-expanded="true"] { background-color: var(--color-accent); }
data-[state=open]:underline  →  .data-\[state\=open\]\:underline[data-state="open"] { text-decoration-line: underline; }

Any aria-/data- variant whose base utility is unknown emits nothing — there is no spurious empty rule.

Container queries (@container)

Mark an element as a query container with @container (or the named @container/<name> form), then size descendants with the @sm:/@md:/@lg:/@xl:/@2xl: container-query variants. These wrap the rule in an @container at-rule rather than @media, and use Tailwind's container-query scale (which differs from the viewport breakpoint scale).

Class / variant Output
@container container-type: inline-size;
@container/sidebar container-type: inline-size; container-name: sidebar;
@sm: @container (min-width: 24rem) { … }
@md: @container (min-width: 28rem) { … }
@lg: @container (min-width: 32rem) { … }
@xl: @container (min-width: 36rem) { … }
@2xl: @container (min-width: 42rem) { … }
governedaihuaihu137 B
<div class="@container">
  <div class="@md:flex">…</div>   →  @container (min-width: 28rem) { .\@md\:flex { display: flex; } }
</div>

Brand tokens (24)

Override any token in a component's @style block via @theme { --color-primary: oklch(...); }.

Token Token
primary / primary-foreground secondary / secondary-foreground
accent / accent-foreground surface / surface-foreground
destructive / destructive-foreground background / foreground
muted / muted-foreground border / ring
info / info-foreground success / success-foreground
warning / warning-foreground neutral / neutral-foreground

The last four pairs (info, success, warning, neutral) are semantic-state tokens added after the original 16-token set — the count above (24) reflects both generations. Use as bg-primary, text-accent, border-muted, ring-ring, bg-success, etc.

Palette

22 color families × 11 shades (50950), matching the Tailwind v4 palette (e.g. bg-red-500, text-slate-700, border-zinc-200). Note that neutral is both a bare brand token (above) and a full 11-shade palette family — they're distinct code paths, so bg-neutral and bg-neutral-500 resolve differently. See the Tailwind v4 color palette for the full swatch list.

Arbitrary values

Use prefix-[value] to bypass the scale for: bg, text, w, h, min-w, max-w, min-h, max-h, p, px, py, m, mx, my, gap, rounded, border, leading, tracking, z, top, right, bottom, left, inset, fill, stroke, shadow.

governedaihuaihu110 B
bg-[#1a1d24]   →  background-color: #1a1d24;
w-[34ch]       →  width: 34ch;
top-[1rem]     →  top: 1rem;

Not yet supported

The following are deliberately out of scope today. Most have an arbitrary-value workaround; the rest require variant-parser changes. Open an issue if you need one promoted.

  • Arbitrary at-rules beyond @media / @container (e.g. @supports)

Worked examples

One input → output pair per notable family.

space-y-4 (Spacing)

governedhtmlhtml32 B
<ul class="space-y-4"> … </ul>
governedcsscss54 B
.space-y-4 { & > * + * { margin-block-start: 1rem; } }

divide-y-2 (Divide — sibling borders)

governedhtmlhtml46 B
<ul class="divide-y-2 border-muted"> … </ul>
governedcsscss54 B
.divide-y-2 { & > * + * { border-block-width: 2px; } }

mx-auto (Margin auto)

governedhtmlhtml32 B
<div class="mx-auto"> … </div>
governedcsscss33 B
.mx-auto { margin-inline: auto; }

max-w-7xl (Named max-width)

governedhtmlhtml42 B
<section class="max-w-7xl"> … </section>
governedcsscss32 B
.max-w-7xl { max-width: 80rem; }

grid-cols-3 (Grid templating)

governedhtmlhtml47 B
<div class="grid grid-cols-3 gap-4"> … </div>
governedcsscss66 B
.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

border-t-4 (Directional border width)

governedhtmlhtml35 B
<div class="border-t-4"> … </div>
governedcsscss38 B
.border-t-4 { border-top-width: 4px; }

absolute top-4 right-4 (Position scale)

governedhtmlhtml53 B
<button class="absolute top-4 right-4"> … </button>
governedcsscss47 B
.top-4 { top: 1rem; }
.right-4 { right: 1rem; }

leading-relaxed (Line-height scale)

governedhtmlhtml36 B
<p class="leading-relaxed"> … </p>
governedcsscss40 B
.leading-relaxed { line-height: 1.625; }

tracking-wide (Letter-spacing scale)

governedhtmlhtml36 B
<h1 class="tracking-wide"> … </h1>
governedcsscss43 B
.tracking-wide { letter-spacing: 0.025em; }

ring-2 ring-blue-500 (Ring width + color)

governedhtmlhtml57 B
<button class="focus:ring-2 ring-blue-500"> … </button>
governedcsscss386 B
.ring-2 {
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.ring-blue-500 { --tw-ring-color: var(--color-blue-500); }

ring-offset-2 (Ring offset width)

governedhtmlhtml45 B
<div class="ring-2 ring-offset-2"> … </div>
governedcsscss47 B
.ring-offset-2 { --tw-ring-offset-width: 2px; }

hover:scale-105 + transition-transform (Motion)

governedhtmlhtml80 B
<button class="transition-transform duration-300 hover:scale-105"> … </button>
governedcsscss241 B
.transition-transform { transition-property: transform; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
.duration-300 { transition-duration: 300ms; }
.hover\:scale-105:hover { transform: scale(1.05); }

animate-spin (Animation with hoisted keyframes)

governedhtmlhtml37 B
<div class="animate-spin"> … </div>
governedcsscss107 B
.animate-spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

aria-expanded: (attribute variant)

governedhtmlhtml54 B
<button class="aria-expanded:bg-accent"> … </button>
governedcsscss90 B
.aria-expanded\:bg-accent[aria-expanded="true"] { background-color: var(--color-accent); }

@container + @md: (container query)

governedhtmlhtml67 B
<div class="@container">
  <div class="@md:flex"> … </div>
</div>
governedcsscss112 B
.\@container { container-type: inline-size; }
@container (min-width: 28rem) {
  .\@md\:flex { display: flex; }
}

See also