이 페이지는 아직 번역되지 않았습니다. 영어 원문 보기

API

Tailwind reference

Every element takes Tailwind CSS classes in its class prop (and conditional ones in classList). NSH resolves them in Rust against Tailwind 4’s default theme: JS passes only the string, each distinct string is parsed once and cached, and variants such as dark: or active: are re-evaluated natively when the appearance, window size or press state changes, without running any JS.

Each utility sets exactly what Tailwind CSS 4 generates for it, with the same meaning as in a browser. This page lists what is supported. For an introduction see Tailwind; for the style keys the utilities set, see the Style reference.

Rust components take no class strings: they style elements with the typed methods of Styled (nsh_core::prelude), named after these utilities and resolving to the same values, Tailwind’s default scales included (px-4 is .px_4(), rounded-2xl .rounded_2xl(), shadow-md .shadow_md(), bg-linear-to-br .bg_linear_to_br()). Colors are values: theme colors, or Tailwind’s palette as nsh_core::element::palette (ZINC.shade(800) is zinc-800). Variants are methods taking a closure of styles: .active(|s| …), .hover(…), .focus(…), .disabled_style(…), .dark(…), .group_active(…), and .style_when(condition, …) for the rest. The Style reference names the method of each style key.

use nsh_core::{element::palette::{RED, ZINC}, prelude::*};

view()
    .flex_row()
    .items_center()
    .gap_3()
    .rounded_2xl()
    .bg(white())
    .p_4()
    .shadow_md()
    .active(|s| s.scale(0.98))
    .transition()
    .dark(|s| s.bg(ZINC.shade(800)))
    .child(
        text("Inbox")
            .text_base()
            .font_weight(FontWeight::SEMIBOLD)
            .text_color(ZINC.shade(900))
            .dark(|s| s.text_color(white())),
    )
    .child(
        text(move || unread.get().to_string())
            .text_color(move || if unread.get() > 0 { RED.shade(500) } else { ZINC.shade(400) }),
    )

#How classes combine

  • Later wins. Among utilities of the same variant level, the one later in the string wins: "p-4 p-2" is p-2. A component can take a class prop and append it to its own classes without tailwind-merge.
  • Variants apply after plain utilities, in Tailwind’s variant order: group-*: (by their state, then by group name), selection:, placeholder:, position (first: …), checked:, indeterminate:, selected:, focus-within:, hover:, focus:, focus-visible:, active:, enabled:, disabled:, aria-busy:, aria-checked:, aria-expanded:, aria-pressed:, aria-selected:, data-*: (by name), motion, max-*: breakpoints widest first, then breakpoints ascending, orientation, direction, dark:, then platform. A class’s highest variant decides, then its next highest, and one more variant comes later (dark:hover: after dark:), as Tailwind sorts them. So "active:bg-red-500 bg-blue-500" is red while pressed.
  • style wins over classes. The inline style is applied on top of the resolved classes. A style key is the CSS property of its name, the one the utilities set, so it replaces that property and nothing else: style={{ paddingLeft: 8 }} beats pl-4 and keeps pr-4. An important utility (!p-4 or p-4!) wins over the inline style too.
  • Text styles inherit. Text utilities on a view (text-white, font-bold, text-center, …) pass to the <Text> and <Input> elements inside it, as in CSS.
  • Display is CSS’s. flex and inline-flex make a row unless a direction utility says otherwise, wherever it is in the string (flex-col flex is a column). A style’s display: "flex" is a row in the same way; views that set no display keep NSH’s column default.

#Units and the theme

Lengths are points (1 = one point on iOS, one dp on Android). Tailwind’s 1rem is 16 points, so the theme matches the web at the same density: one spacing step is 4 points (p-4 = 16 points), text-base is 16 points.

#Spacing values

Utilities that take a spacing value (padding, margin, gap, inset, width, height, basis, translate, leading) accept:

ValueExampleResult
Steps (quarter steps allowed)p-4, gap-1.5, m-0.25step × 4 points
pxp-px, -mt-px1 point
0m-00
Fraction (inset, width, height, basis, translate)w-1/2, left-1/3percentage of the parent
full (the same)w-full, inset-full100%
auto (margin, inset, width, height, basis)mx-auto, w-auto"auto"
Arbitraryp-[13px], w-[42%], mt-[1.5rem]the given length

Margins, insets, translate, rotate, skew, scale, z, hue-rotate, tracking, underline-offset, outline-offset, grid lines and gradient angles take a leading - for negative values: -mt-2, -translate-x-1/2, -rotate-6. Tailwind has no negative form of the others (-p-4, -gap-2, -w-4), and neither has NSH.

#Colors

The full Tailwind 4 palette is built in: red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose, slate, gray, zinc, neutral, stone, mauve, olive, mist, taupe, each in shades 50, 100–900, 950; plus black, white and transparent. Your own colors come from nsh.json (see Theme customization).

Every color utility takes:

FormExample
A theme colorbg-sky-500, text-brand
An opacity modifier (percent)bg-black/50, ring-black/5
An arbitrary opacitytext-black/[0.35]
An arbitrary colorbg-[#0ea5e9], border-[rgb(0_0_0_/_0.1)], text-[oklch(70%_0.2_50)]
An arbitrary color with a modifierbg-[rgb(0_0_255)]/25

currentColor and inherit are not color values. As in a browser, a border, an outline or a ring without a color class is drawn in the element’s text color, its own or the one it inherits (<View class="text-white"><View class="border ring-2" /></View> draws both white), and so is a border whose width the style prop sets without a color.

#Arbitrary values

Square brackets pass a value the theme does not have: w-[37px], grid-cols-[200px_1fr], bg-[linear-gradient(45deg,red,blue)].

  • _ stands for a space (grid-cols-[1fr_2fr]); write \_ for a literal underscore.
  • Lengths: a bare number or px (points), pt (4/3 of a point, as in CSS), rem (16 points), and % where percentages make sense.
  • Angles (rotate-[...], hue-rotate-[...], bg-linear-[...]): deg, rad, grad, turn.
  • Times (duration-[...], delay-[...]): ms or s; a bare number is milliseconds.
  • Type hints settle ambiguous values: text-[length:22px] is a size, text-[color:#333] a color; border-[length:3px] likewise.

Arbitrary CSS properties ([mask-type:luminance]) are not supported.

#Layout

ClassSets
flex, inline-flexdisplay: "flex", and a row unless a direction utility is present
grid, inline-griddisplay: "grid"
block, flow-rootblock layout or an independent block formatting context
box-border, box-contentdimensions include borders and padding, or content alone
w/h/size-min, w/h/size-max, w/h/size-fitTaffy intrinsic sizes: min-content, max-content, fit-content
inline, inline-blockdisplay: "block": what a browser computes for them in a flex or grid parent
hiddendisplay: "none"
relative, absoluteposition
staticposition: "static": in the flow, its insets ignored ; absolute descendants use their nearest positioned ancestor
stickyposition: "sticky": in the flow, it sticks top (left in a horizontal scroll view) within the scroll view around it while its parent is in view
fixedposition: "fixed": an element laid out in its root view’s box (the window or its modal) above that root view’s children, in place while what is around it scrolls
inset-<n>, inset-x-<n>, inset-y-<n>top / right / bottom / left
top-<n>, right-<n>, bottom-<n>, left-<n>the matching offset
start-<n>, end-<n>start / end (direction-aware)
z-<n>, z-auto, z-[<n>]zIndex (z-auto is 0)
visiblevisibility: "visible"
invisible, collapsevisibility: "hidden" (keeps its space)
overflow-hidden, overflow-clip, overflow-x-hidden, overflow-y-hiddenoverflow: "hidden"
overflow-visibleoverflow: "visible"
aspect-square, aspect-video, aspect-<a>/<b>, aspect-[<a>/<b>], aspect-autoaspectRatio (1, 16/9, a/b, none)

Scrolling is an element, not a class: overflow-auto and overflow-scroll are not supported; use scroll.

#Flexbox and grid

ClassSets
flex-row, flex-row-reverse, flex-col, flex-col-reverseflexDirection
flex-wrap, flex-wrap-reverse, flex-nowrapflexWrap
flex-1grow 1, shrink 1, basis 0
flex-<n>grow n, shrink 1, basis 0
flex-autogrow 1, shrink 1, basis auto
flex-initialgrow 0, shrink 1, basis auto
flex-nonegrow 0, shrink 0, basis auto
flex-[<grow>], flex-[<grow>_<shrink>_<basis>]the CSS shorthand: flex-[2], flex-[3_0_50%]
grow, grow-<n>, grow-[<n>]flexGrow (bare: 1)
shrink, shrink-<n>, shrink-[<n>]flexShrink (bare: 1)
basis-<n>flexBasis (spacing, fraction, full, auto, arbitrary)
justify-start, justify-end, justify-center, justify-between, justify-around, justify-evenly, justify-stretch, justify-normaljustifyContent
items-start, items-end, items-center, items-baseline, items-stretchalignItems
self-auto, self-start, self-end, self-center, self-stretch, self-baselinealignSelf
content-start, content-end, content-center, content-between, content-around, content-evenly, content-stretch, content-normalalignContent
justify-items-start, -end, -center, -stretch, -normaljustifyItems
justify-self-auto, -start, -end, -center, -stretchjustifySelf
place-content-center, -start, -end, -between, -stretchalignContent and justifyContent
place-items-center, -start, -end, -stretchalignItems and justifyItems
place-self-auto, -center, -start, -end, -stretchalignSelf and justifySelf
gap-<n>, gap-x-<n>, gap-y-<n>gap, columnGap, rowGap
space-x-<n>, space-y-<n> (and negative)a margin on each child but the last: the end margin (space-x) or the bottom one (space-y), under the child’s own margins, as in Tailwind CSS; it adds to a gap
space-x-reverse, space-y-reversethe margin on the start / top side instead (children in reverse order)
grid-cols-<n>gridTemplateColumns: "repeat(n, minmax(0, 1fr))"
grid-cols-[<tracks>], grid-cols-nonegridTemplateColumns (grid-cols-[200px_1fr])
grid-rows-<n>, grid-rows-[<tracks>], grid-rows-nonegridTemplateRows
col-span-<n>, col-span-full, col-auto, col-<n>, col-[<value>]gridColumn
col-start-<n>, col-end-<n> (and -auto)gridColumnStart, gridColumnEnd
row-span-<n>, row-span-full, row-auto, row-<n>, row-[<value>]gridRow
row-start-<n>, row-end-<n> (and -auto)gridRowStart, gridRowEnd
grid-flow-row, grid-flow-col, grid-flow-dense, grid-flow-row-dense, grid-flow-col-densegridAutoFlow
auto-cols-auto, -min, -max, -fr, auto-cols-[<track>]gridAutoColumns
auto-rows-auto, -min, -max, -fr, auto-rows-[<track>]gridAutoRows

#Spacing

ClassSets
p-<n>, px-<n>, py-<n>padding, paddingHorizontal, paddingVertical
pt-<n>, pr-<n>, pb-<n>, pl-<n>paddingTop / Right / Bottom / Left
ps-<n>, pe-<n>paddingStart, paddingEnd (direction-aware)
m-<n>, mx-<n>, my-<n>margin, marginHorizontal, marginVertical
mt-<n>, mr-<n>, mb-<n>, ml-<n>marginTop / Right / Bottom / Left
ms-<n>, me-<n>marginStart, marginEnd (direction-aware)

#Sizing

ClassSets
w-<n>, h-<n>width, height (spacing, fraction, full, auto, arbitrary)
size-<n>width and height
min-w-<n>, max-w-<n>, min-h-<n>, max-h-<n>the matching limit
w-screen, w-dvw, w-svw, w-lvwthe window width (also on min-w- / max-w-)
h-screen, h-dvh, h-svh, h-lvhthe window height (also on min-h- / max-h-)
w-auto, h-autoauto (sized by content)
max-w-none, max-h-noneno limit
w-<container>, min-w-<container>, max-w-<container>a container width (below)

Container widths (points): 3xs 256, 2xs 288, xs 320, sm 384, md 448, lg 512, xl 576, 2xl 672, 3xl 768, 4xl 896, 5xl 1024, 6xl 1152, 7xl 1280; prose is 65 times the width of the element’s font’s 0 (CSS’s 65ch), as in Tailwind CSS.

#Typography

#Font

ClassSets
font-sansthe system font
font-serif, font-monofontFamily: "serif" / "monospace"
font-thin (100), font-extralight (200), font-light (300), font-normal (400), font-medium (500), font-semibold (600), font-bold (700), font-extrabold (800), font-black (900)fontWeight
font-[<weight>], font-[<family>]a numeric weight, otherwise a family: font-[650], font-[Inter]
italic, not-italicfontStyle
normal-nums, small-caps, oldstyle-nums, lining-nums, tabular-nums, proportional-numsfontVariant (they combine; normal-nums resets the number forms)

#Size, color and line height

text-<size> sets the font size and Tailwind’s matching line height, which a leading-* class replaces wherever it is in the string and whatever its variant (leading-tight md:text-lg keeps the tight leading):

ClassSizeLine height
text-xs1216
text-sm1420
text-base1624
text-lg1828
text-xl2028
text-2xl2432
text-3xl3036
text-4xl3640
text-5xl481×
text-6xl601×
text-7xl721×
text-8xl961×
text-9xl1281×
ClassSets
text-<size>/<leading>size and line height: text-sm/6 (24 points), text-lg/tight
text-[<length>]fontSize: text-[22px], text-[length:22px]
text-<color>color
leading-none (1), leading-tight (1.25), leading-snug (1.375), leading-normal (1.5), leading-relaxed (1.625), leading-loose (2)lineHeight as a multiple of the font size
leading-<n>, leading-[<length>]lineHeight in points (leading-6 = 24)
leading-[<number>]lineHeight as a multiple of the font size (leading-[1.5]), inherited as that multiplier; em and % compute a length at the element’s font size before inheritance
tracking-tighter (-0.05em), tracking-tight (-0.025em), tracking-normal (0), tracking-wide (0.025em), tracking-wider (0.05em), tracking-widest (0.1em)letterSpacing relative to the font size
tracking-[<value>]letterSpacing: tracking-[0.2em], tracking-[1px]

#Alignment, case and wrapping

ClassSets
text-left, text-center, text-right, text-justifytextAlign
text-start, text-endtextAlign: "start" / "end": the start or end of the line in the layout direction
align-baseline, align-text-top, align-text-bottom, align-middleverticalAlign (views and images inside a text)
uppercase, lowercase, capitalize, normal-casetextTransform
truncateone line, tail ellipsis, no wrapping, overflow: hidden (on a view: its texts do not wrap)
line-clamp-<n>, line-clamp-nonenumberOfLines (none shows every line)
text-ellipsis, text-cliptextOverflow: "ellipsis" / "clip"
whitespace-nowrap, text-nowraplines never wrap; on a view, the lines of the texts in it (inherited, as CSS’s white-space)
whitespace-normal, text-wrap, text-balance, text-prettylines wrap (balancing is not done)
select-text, select-noneuserSelect: "text" / "none"; on a view, of the texts in it that set none
select-autouserSelect: "auto": the view around it decides, as CSS’s user-select: auto (select-none md:select-auto)

#Decoration and shadow

ClassSets
underline, line-through, no-underlinetextDecorationLine
decoration-solid, decoration-double, decoration-dotted, decoration-dashed, decoration-wavytextDecorationStyle
decoration-<n>, decoration-[<length>]textDecorationThickness
decoration-auto, decoration-from-fonttextDecorationThickness: "auto"
decoration-<color>textDecorationColor
underline-offset-<n>, underline-offset-[<length>], underline-offset-autotextUnderlineOffset
text-shadow-2xs, -xs, -sm, -md, -lg; /<alpha>a text shadow from the theme (one layer: the widest of the theme’s); the modifier is the layers’ alpha: text-shadow-md/20
text-shadow-<color>, text-shadow-currentits color, at the size’s alpha
text-shadow-noneremoves it

Tailwind’s text shadows have several layers; natively one shadow is drawn, the widest layer.

#Inputs

ClassSets
placeholder:text-<color>placeholderColor
selection:bg-<color>selectionColor (the highlight of an input’s or a selectable text’s selection, and of those inside the element)
caret-<color>the cursor color

#Backgrounds

ClassSets
bg-<color>backgroundColor
bg-[<gradient>]backgroundImage: bg-[linear-gradient(45deg,red,blue)], bg-[radial-gradient(...)]
bg-linear-to-t, -tr, -r, -br, -b, -bl, -l, -tla linear gradient toward a side or corner (bg-gradient-to-* is the v3 name)
bg-linear-<angle>, bg-linear-[<angle>]a linear gradient at an angle: bg-linear-45, -bg-linear-12, bg-linear-[0.25turn]
bg-radiala radial gradient from the center
bg-conic, bg-conic-<angle>a conic gradient, optionally starting at an angle
from-<color>, via-<color>, to-<color>the gradient’s stops (default transparent at the ends)
from-<p>%, via-<p>%, to-<p>%stop positions: via-40%, from-[15%]
bg-noneremoves the gradient

Gradient utilities mix their colors in Oklab, as Tailwind CSS writes them (in oklab); at an arbitrary position (bg-linear-[25deg], bg-conic-[0.25turn]) they follow CSS’s default, Oklab with the palette’s colors and sRGB when every stop is a hex, rgb(), hsl() or named color.

view()
    .h_32()
    .rounded_2xl()
    .bg_linear_to_br()
    .gradient_from(INDIGO.shade(500))
    .gradient_via(PURPLE.shade(500))
    .gradient_via_position(percentage(0.4))
    .gradient_to(PINK.shade(500))

#Borders

ClassSets
border, border-<n>, border-[<length>]borderWidth (bare: 1)
border-x, border-y, border-t, border-r, border-b, border-l, border-s, border-e (with -<n> or bare)the matching sides’ widths
border-<color>, border-t-<color>, …borderColor and the per-side colors
border-solid, border-dashed, border-dottedborderStyle
border-none, border-hiddenborderStyle: "none" / "hidden": no border whatever the width classes, in any order (md:border-solid shows it again)
rounded, rounded-<size>, rounded-none, rounded-full, rounded-[<length>]borderRadius (bare: sm)
rounded-t-, -r-, -b-, -l-, -tl-, -tr-, -br-, -bl-the matching corners
rounded-s-, -e-, -ss-, -se-, -es-, -ee-start / end corners (direction-aware): borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius
outline, outline-<n>, outline-[<length>]outlineWidth (bare: 1), solid unless a style class is anywhere in the string (outline-dashed outline-2 is dashed, outline-none outline-2 draws nothing)
outline-<color>outlineColor
outline-solid, outline-dashed, outline-dotted, outline-none, outline-hiddenoutlineStyle; a style alone is CSS’s medium width, 3 points
outline-offset-<n>, outline-offset-[<length>]outlineOffset

Radius sizes (points): xs 2, sm 4, md 6, lg 8, xl 12, 2xl 16, 3xl 24, 4xl 32, full 9999.

#Rings

Rings are box shadows with a spread, drawn outside the border without taking space.

ClassSets
ring, ring-<n>, ring-[<length>]a ring of that width (bare: 1)
ring-<color>its color (default the element’s text color)
ring-insetdraws the ring inside
ring-offset-<n>, ring-offset-<color>a gap between element and ring (default white)
inset-ring, inset-ring-<n>, inset-ring-<color>an inner ring

#Effects

ClassSets
shadow-2xs, shadow-xs, shadow-sm, shadow, shadow-md, shadow-lg, shadow-xl, shadow-2xl; /<alpha>boxShadow from the theme; the modifier is the layers’ alpha: shadow-xl/20
shadow-[<box-shadow>]an arbitrary shadow: shadow-[0_8px_24px_rgb(0_0_0_/_0.12)]
shadow-<color>, shadow-currentrecolors the shadow layers, at the size’s alpha: shadow-indigo-500/40
shadow-noneno shadow
inset-shadow-2xs, -xs, -sm, inset-shadow, inset-shadow-[...], inset-shadow-<color>, inset-shadow-nonean inner shadow
opacity-<n>, opacity-[<value>]opacity: opacity-50 = 0.5
mix-blend-<mode>mixBlendMode: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity, plus-darker, plus-lighter

Shadows, rings and inset shadows combine into one boxShadow list, as in CSS. A shadow color replaces each layer’s color, alpha too, as Tailwind’s --tw-shadow-color: shadow-md shadow-red-500 is an opaque red shadow, shadow-md/20 shadow-red-500 one at 20%.

#Filters

ClassSets
blur, blur-xs (4), -sm (8), -md (12), -lg (16), -xl (24), -2xl (40), -3xl (64), blur-none, blur-[<length>]blur()
brightness-<n>, contrast-<n>, saturate-<n>percentage factors: brightness-125 = 1.25
grayscale, grayscale-<n>, invert, invert-<n>, sepia, sepia-<n>bare: 100%
hue-rotate-<deg>, -hue-rotate-<deg>hue-rotate()
drop-shadow, drop-shadow-xs, -sm, -md, -lg, -xl, -2xl, drop-shadow-[...], drop-shadow-none; drop-shadow-<color>, drop-shadow-current; /<alpha> on eithera drop-shadow() per layer, after the other filters; a color replaces the layers’, at the size’s alpha; the web, Linux, Windows and GPUI draw every layer, iOS, macOS and Android the widest
drop-shadow-noneremoves it
filter-noneremoves all filters
backdrop-blur, backdrop-blur-<size>, backdrop-blur-[<length>]blurs what is behind the view
backdrop-brightness-<n>, backdrop-contrast-<n>, backdrop-grayscale, backdrop-hue-rotate-<deg>, backdrop-invert, backdrop-opacity-<n>, backdrop-saturate-<n>, backdrop-sepiabackdrop filters
backdrop-filter-noneremoves them

#Transforms

ClassSets
translate-x-<n>, translate-y-<n>, translate-<n>translate (spacing, full, fractions of the element’s own size: -translate-x-1/2, arbitrary)
rotate-<deg>, rotate-[<angle>]rotate
rotate-x-<deg>, rotate-y-<deg>, rotate-z-<deg>3D rotation (in transform, after the translation, the rotation and the scale)
scale-<pct>, scale-x-<pct>, scale-y-<pct>, scale-[<factor>]scale: scale-95 = 0.95, -scale-x-100 mirrors
skew-<deg>, skew-x-<deg>, skew-y-<deg>skew, in transform (not on Android)
perspective-dramatic (100), -near (300), -normal (500), -midrange (800), -distant (1200), perspective-[<length>], perspective-nonedepth for the 3D rotations of the element’s children, seen from its center (CSS’s perspective: <View class="perspective-near"><View class="rotate-y-45" /></View>)
origin-center, -top, -top-right, -right, -bottom-right, -bottom, -bottom-left, -left, -top-left, origin-[<value>]transformOrigin
backface-hidden, backface-visiblebackfaceVisibility
transform-noneclears the 3D rotations and the skews (CSS’s transform: none)
translate-none, rotate-none, scale-noneclears the translation, the rotation, the scale

Transform utilities compose like CSS: translate-*, rotate-* and scale-* set the translate, rotate and scale properties and combine regardless of order, then transform applies (rotate-x-*, skew-*). The style prop’s keys of the same names replace only their own property: style={{ scale: 1.1 }} replaces scale-95 and keeps rotate-3. transform, transform-gpu, transform-cpu and transform-flat are accepted and do nothing: NSH composes every transform alike, flat. Translations by a fraction of the size are resolved against the element’s frame and follow it when it resizes.

#Transitions and animation

ClassSets
transitioncolors, opacity, shadow and transform; 150 ms, cubic-bezier(0.4, 0, 0.2, 1)
transition-all, transition-colors, transition-opacity, transition-shadow, transition-transformthe animated properties
transition-noneno transition
duration-<ms>, duration-[<time>]transitionDuration: duration-300, duration-[0.4s]
delay-<ms>, delay-[<time>]transitionDelay
ease-linear, ease-in, ease-out, ease-in-out, ease-initial, ease-[cubic-bezier(...)]transitionTimingFunction
animate-spin, animate-ping, animate-pulse, animate-bouncea native keyframe animation, repeated forever
animate-nonestops it

Transitions run on the UI thread when a value changes, including when a variant starts or stops matching, so transition active:scale-95 animates the press without JS. Wrap animations in motion-safe: to respect the reduce-motion setting.

#Interactivity

ClassSets
pointer-events-none, pointer-events-autopointerEvents: "none" / "auto": whether the view is a target for touches and the pointer, inherited as in CSS: inside a pointer-events-none view, a pointer-events-auto one is a target again
cursor-<name>, cursor-[<name>]cursor: cursor-pointer, cursor-grab, cursor-not-allowed, … (every CSS cursor keyword)
select-none, select-text, select-autotext selection (see Typography)

#SVG

ClassSets
fill-<color>, fill-none, fill-current, fill-inheritfill (fill-current is currentColor)
stroke-<color>, stroke-none, stroke-current, stroke-inheritstroke
stroke-<number>, stroke-[<length>]strokeWidth

#Images

ClassSets
object-cover, object-contain, object-fill, object-none, object-scale-downobjectFit (fill stretches, none keeps the natural size, placed at objectPosition, scale-down is the same, shrunk to fit where larger); images and videos
object-top, object-bottom, object-left, object-right, object-center, object-top-left, object-top-right, object-bottom-left, object-bottom-right, object-[<position>]objectPosition (object-left-top, … are the same as object-top-left, …)
tint-<color>tintColor (recolors template images)

#Accepted without effect

These utilities are rendering hints, or what every native view already is; they parse without a warning and change nothing: antialiased, subpixel-antialiased, isolation-auto, box-border, appearance-none, appearance-auto, will-change-auto, will-change-scroll, will-change-contents, will-change-transform, will-change-[<value>], transform, transform-gpu, transform-cpu, transform-flat. Scrolling, snapping and overscroll are props of scroll.

#Not supported

peer-* variants, pseudo-elements (before:, after:), arbitrary properties ([prop:value]), overflow-auto / overflow-scroll, divide-*, columns-*, float-*, container, container queries, order-*, transform-3d, select-all, border-double / outline-double, intrinsic min/max constraints (such as max-w-max), snap-*, scroll-*, overscroll-*, touch-* and isolate are unknown classes. nsh build and nsh dev warn about unknown classes they find in your source (file:line:col: unknown class '...'), and the runtime logs each unknown class once.

#Variants

Variants make a utility conditional: dark:bg-zinc-900, md:flex-row, active:opacity-70. They stack (dark:active:bg-zinc-700) and are evaluated natively whenever what they depend on changes.

#Appearance and environment

VariantApplies whenRust
dark:the appearance is dark.dark(|s| …)
ios:running on iOS or Mac Catalyst.when(os() == Os::Ios, …)
android:running on Android.when(os() == Os::Android, …)
portrait:, landscape:the window is taller than wide / wider than tall.style_when(move || window().height > window().width, …)
ltr:, rtl:the layout direction.style_when(rtl, …)
motion-safe:, motion-reduce:the user has not / has asked for reduced motion.style_when(reduce_motion, …)

#Breakpoints

Breakpoints compare the window width in points.

VariantMin width
sm:640
md:768
lg:1024
xl:1280
2xl:1536
FormExampleApplies when
<bp>:md:p-8width ≥ breakpoint
max-<bp>:max-md:p-1width < breakpoint
min-[<length>]:min-[600px]:grid-cols-3width ≥ the length
max-[<length>]:max-[400px]:text-smwidth < the length

A phone in portrait (390 points wide) matches none of the default breakpoints; a tablet or a phone in landscape matches several. In Rust, a breakpoint is a condition on the window: .style_when(move || window().width >= px(768.0), |s| s.p_8()) is md:p-8.

#Interaction states

States are tracked by the platform only for elements whose classes use them, and changes apply natively, with no JS round trip.

VariantApplies whenRust
active:the element is pressed.active(|s| …)
hover:a pointer is over it (iPad pointer, Mac Catalyst, Android mouse).hover(|s| …)
focus:, focus-visible:the input has focus.focus(|s| …)
focus-within:the element or a descendant has focus (an Overlay’s content is a descendant of the element it is in).focus_within(…)
disabled:the element has the disabled prop.disabled_style(|s| …)
enabled:the element does not have the disabled prop
selected:the element is selected: a Button’s selected, or accessibilityState.selected
checked:the element is checked: accessibilityState.checked is true ("mixed" is not checked)
indeterminate:the element is indeterminate: accessibilityState.checked is "mixed"
aria-expanded:the element is expanded: accessibilityState.expanded is true (a Popover’s or Menu’s trigger while its popup is open)
aria-pressed:the element is a toggle button that is on: accessibilityState.pressed is true ("mixed" is not pressed; not active:, a press in progress).aria_pressed(|s| …)
aria-busy:the element is busy: accessibilityState.busy is true
aria-checked:the element is checked: accessibilityState.checked is true, as checked:
aria-selected:the element is selected: accessibilityState.selected is true, as selected:
data-<name>:the element has the boolean data-* attribute name (Tailwind’s &[data-<name>]; names of lower case letters, digits and -): what a component’s part shows beyond its states, a calendar’s day at the start of a range data-range-startInteractive::project_data(name, …) sets one

The same states as style objects are the activeStyle, hoverStyle, focusStyle, disabledStyle, checkedStyle, indeterminateStyle, expandedStyle and pressedStyle props of every element (and a Button’s selectedStyle); they go over the element’s style and classes.

disabled works on any element: it applies disabled: and removes the element’s press handlers, so it shows no press feedback either.

view()
    .on_press(save)
    .disabled(saving)
    .rounded_lg()
    .bg(BLUE.shade(600))
    .px_4()
    .py_2()
    .transition()
    .active(|s| s.scale(0.95).bg(BLUE.shade(700)))
    .disabled_style(|s| s.opacity(0.4))
    .child(text("Save").font_weight(FontWeight::MEDIUM).text_color(white()))

#Groups

Mark an ancestor with group and style descendants by its state with group-<state>:. Name groups to nest them: group/card and group-hover/card:.

VariantApplies when the group isRust
group-active:pressed.group_active(…), .group_active_named(name, …)
group-hover:hovered.group_hover(…), .group_hover_named(name, …)
group-focus:, group-focus-visible:focused
group-focus-within:focused or containing focus.group_focus_within(…), .group_focus_within_named(name, …)
group-disabled:disabled
group-selected:selected
group-checked:checked
group-indeterminate:indeterminate
group-aria-expanded:expanded
group-aria-pressed:a toggle button that is on
group-aria-busy:, group-aria-checked:, group-aria-selected:busy, checked, selected
group-data-<name>:showing the data-* attribute name
view()
    .on_press(open)
    .group_named("row")
    .flex_row()
    .items_center()
    .gap_3()
    .p_3()
    .active(|s| s.bg(ZINC.shade(100)))
    .child(
        text("Settings")
            .flex_1()
            .text_color(ZINC.shade(900))
            .group_active_named("row", |s| s.text_color(BLUE.shade(600))),
    )
    .child(
        text("›")
            .text_color(ZINC.shade(400))
            .group_active_named("row", |s| s.translate_x(px(4.0)))
            .transition_transform(),
    )

#Position among siblings

VariantApplies to
first:the first child
last:the last child
only:the only child
odd:the 1st, 3rd, … child
even:the 2nd, 4th, … child
each(items, |item: &Item| item.id, move |item, index| {
    text(move || item.with(|i| i.name.clone()))
        .border_b(px(1.0))
        .border_color(ZINC.shade(200))
        .py_3()
        .style_when(move || index.get() + 1 == items.with(Vec::len), |s| s.border_b(px(0.0)))
})

#Placeholder and selection

placeholder: applies to an <Input>’s placeholder and only takes a text color: placeholder:text-zinc-400 (the style key placeholderColor). selection: applies to the selection of an <Input> or a selectable <Text>, and on any element to those inside it (Tailwind’s & *::selection; the nearest element’s wins), and takes its background, the highlight: selection:bg-violet-200 (the style key selectionColor, which also tints an input’s caret where the platform draws them in one color).

#Important

! before or after a utility (!p-4, p-4!) makes it win over every other class and over the inline style.

#Theme customization

Extend the theme in the "tailwind" object of your app’s nsh.json. Entries with a new name are added; entries with an existing name replace the default. Lengths are points. The theme is checked when the app is bundled: an unknown key or an invalid value is a build error.

{
  "name": "My App",
  "id": "com.example.myapp",
  "tailwind": {
    "colors": {
      "brand": { "50": "#f5f3ff", "500": "#7c3aed", "600": "#6d28d9", "DEFAULT": "#7c3aed" },
      "accent": "#f59e0b"
    },
    "spacing": 4,
    "breakpoints": { "tablet": 600 },
    "fontFamily": { "display": "Inter" },
    "fontSize": { "huge": [48, 1.1] },
    "fontWeight": { "heavy": 850 },
    "radius": { "card": 14 },
    "shadow": { "card": "0 2px 8px rgb(0 0 0 / 0.12)" },
    "insetShadow": { "well": "inset 0 2px 6px rgb(0 0 0 / 0.1)" },
    "dropShadow": { "icon": "0 2px 4px rgb(0 0 0 / 0.2)" },
    "tracking": { "label": 0.08 },
    "leading": { "dense": 1.15 },
    "blur": { "glass": 20 },
    "perspective": { "card": 700 },
    "aspect": { "photo": 1.5 },
    "ease": { "snappy": [0.2, 0, 0, 1] },
    "container": { "content": 680 }
  }
}

With this theme, bg-brand-500, bg-brand (the DEFAULT shade), text-accent, tablet:flex-row, font-display, text-huge, font-heavy, rounded-card, shadow-card, inset-shadow-well, drop-shadow-icon, tracking-label, leading-dense, blur-glass, perspective-card, aspect-photo, ease-snappy and max-w-content all work.

KeyValueUsed by
colors{ name: color } or { name: { shade: color } }; DEFAULT names the bare color. Any CSS color syntax.every color utility
spacingpoints per step (default 4)p-*, m-*, gap-*, w-*, …
rempoints per rem (default 16)
breakpoints{ name: width }breakpoint variants (sorted by width)
container{ name: width }w-*, min-w-*, max-w-*
fontFamily{ name: family } (a system family or the name of a bundled font)font-*
fontSize{ name: size } or { name: [size, lineHeightMultiple] }text-*
fontWeight{ name: 1–1000 }font-*
tracking{ name: em }tracking-*
leading{ name: multiple }leading-*
radius{ name: points }rounded-*
shadow, insetShadow, dropShadow{ name: "CSS box-shadow" }shadow-*, inset-shadow-*, drop-shadow-*
blur{ name: points }blur-*, backdrop-blur-*
perspective{ name: points }perspective-*
aspect{ name: ratio }aspect-*
ease{ name: [x1, y1, x2, y2] }ease-*