Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tailwind Classes (tw!)

The tw! macro compiles Tailwind-style utility class strings into gpui::StyleRefinement mutations at build time. It is invoked automatically when you use the class="..." attribute on any element in view!, or you can call it directly.

Basic Usage

In view!, the class attribute is expanded through tw!:

#![allow(unused)]
fn main() {
view! {
    <div class="flex flex-col gap-3 p-4 bg-[#505050] w-[500px] h-[500px] justify-center items-center text-white">
        <button class="p-2 bg-[#0000ff] hover:bg-[#000088] rounded">{"Click"}</button>
    </div>
}
}

You can also call tw! directly, though this is rarely needed:

#![allow(unused)]
fn main() {
let style = tw!("flex p-4 bg-white");
}

The macro produces a vgui::TwStyle struct with four closures: base, hover, focus, and active. The view! macro wires these to the appropriate gpui pseudo-state handlers automatically.

Unknown classes are silently skipped — the macro does not error on unrecognized utilities.

Variants

Three variant prefixes are supported, each applying styles only in the corresponding interaction state:

PrefixStateExample
hover:Mouse hoverhover:bg-[#000088]
focus:Keyboard focusfocus:border-blue-500
active:Mouse downactive:bg-[#000066]
#![allow(unused)]
fn main() {
view! {
    <button class="bg-blue-600 hover:bg-blue-700 active:bg-blue-800 focus:ring-2 text-white px-4 py-2 rounded">
        {"Save"}
    </button>
}
}

Variants can be stacked with any utility class: hover:text-white, focus:outline-none, active:scale-95 (if supported).

Responsive Breakpoints

Four responsive prefixes apply styles only when the viewport width meets the threshold:

PrefixMin widthExample
sm:≥ 640pxsm:flex-row
md:≥ 768pxmd:flex-row
lg:≥ 1024pxlg:text-lg
xl:≥ 1280pxxl:grid-cols-4
#![allow(unused)]
fn main() {
view! {
    <div class="flex-col md:flex-row">
        {"Stacks on small screens, rows on medium and up."}
    </div>
}
}

Breakpoint closures are applied via __apply_breakpoint_styles reading the viewport width set during render. Each prefix generates a closure that checks the current width and applies its styles only when the threshold is met.

Dynamic Class Composition

The twc! macro composes conditional Tailwind classes at runtime. It takes a base string plus zero or more Option<&str> arguments, including only the ones that are Some:

#![allow(unused)]
fn main() {
view! {
    <button class={twc!(
        "p-2 rounded text-white",
        (delta > 0).then_some("bg-blue-500 hover:bg-blue-600"),
        (delta < 0).then_some("bg-red-500 hover:bg-red-600"),
        (count.get() == 0).then_some("bg-gray-500")
    )}>
        {label}
    </button>
}
}

twc! returns a TwStyle with last-write-wins semantics per CSS field. When multiple conditional classes set the same property, the last matching one wins.

TwClass builder

For programmatic construction, TwClass provides a builder API:

#![allow(unused)]
fn main() {
let cls = TwClass::new()
    .add("p-4")
    .add_if(some_cond, "bg-red-500");
}

TwClassSource trait

TwClassSource is implemented for &str, String, Option<T>, and TwClass, allowing any of these to be used where a class source is expected.

IntoTwStyle trait

IntoTwStyle converts class sources into TwStyle. Using class={twc!(...)} or class={some_string} (a non-literal expression) routes through IntoTwStyle, enabling dynamic class composition at runtime.

tw_dynamic runtime interpreter

tw_dynamic(classes: &str) interprets a class string at runtime, producing a TwStyle. This is the runtime counterpart to the compile-time tw! macro, useful when class strings are not known at compile time.

For animate-* and transition-* classes, see Animations & Transitions.

Arbitrary Values

Arbitrary values use the [...] bracket syntax:

#![allow(unused)]
fn main() {
class="bg-[#0000ff] w-[500px] h-[300px] text-[#ff0000] rounded-[8px] p-[12px]"
}

Supported arbitrary value types:

CategorySyntaxExample
Colors[#hex]bg-[#ff0000]
Colors[rgb(r,g,b)]bg-[rgb(255,0,0)]
Colors[rgba(r,g,b,a)]bg-[rgba(0,0,255,0.5)]
Lengths[Npx]w-[500px]
Lengths[Nrem]w-[20rem]
Lengths[N%]w-[50%]
Lengths[N] (bare)w-[200] (treated as px)

Opacity modifier

Color utilities accept an /NN opacity suffix:

#![allow(unused)]
fn main() {
class="bg-blue-500/50 text-black/75"
}

The /NN value (0–100) sets the alpha channel of the color.

Supported Utilities

Display

ClassEffect
flexdisplay: flex
blockdisplay: block
hiddendisplay: none
griddisplay: grid
inline-flexdisplay: flex

Flex direction

flex-row, flex-col, flex-row-reverse, flex-col-reverse

Flex wrap

flex-wrap, flex-nowrap, flex-wrap-reverse

Flex grow / shrink

ClassEffect
flex-1grow=1, shrink=1, basis=0
flex-autogrow=1, shrink=1, basis=auto
flex-nonegrow=0, shrink=0, basis=auto
flex-growgrow=1
flex-grow-0grow=0
flex-shrinkshrink=1
flex-shrink-0shrink=0
flex-grow-Ngrow=N (arbitrary number)
flex-shrink-Nshrink=N

Justify content

justify-start, justify-end, justify-center, justify-between, justify-around, justify-evenly

Align items

items-start, items-end, items-center, items-baseline, items-stretch

Align self

self-start, self-end, self-center, self-stretch, self-baseline

Align content

content-center, content-start, content-end, content-between, content-around, content-stretch, content-evenly

Position

relative, absolute, static

Overflow

overflow-hidden, overflow-scroll, overflow-auto, overflow-visible, overflow-x-*, overflow-y-*

Visibility

visible, invisible

Spacing

The spacing scale maps class suffixes to pixel values:

SuffixpxSuffixpxSuffixpx
004161248
px15201456
0.526241664
147282080
1.568322496
2893632128
2.510104048192
312114496384

Padding utilities: p-N (all), px-N (inline), py-N (block), pt-N, pr-N, pb-N, pl-N, ps-N, pe-N.

Margin utilities: m-N, mx-N, my-N, mt-N, mr-N, mb-N, ml-N, ms-N, me-N. Also m-auto, mx-auto, my-auto, mt-auto, mr-auto, mb-auto, ml-auto.

Gap

gap-N, gap-x-N, gap-y-N

Sizing

ClassEffect
w-fullwidth: 100%
w-autowidth: auto
w-fitwidth: auto
w-screenwidth: 100%
h-fullheight: 100%
h-autoheight: auto
h-fitheight: auto
h-screenheight: 100%
min-w-fullmin-width: 100%
min-w-automin-width: auto
min-h-fullmin-height: 100%
min-h-automin-height: auto
max-w-fullmax-width: 100%
max-w-nonemax-width: auto
max-h-fullmax-height: 100%
max-h-nonemax-height: auto

Arbitrary: w-[500px], h-[300px], min-w-[200px], max-h-[400px].

Colors

22 named color palettes, each with 11 shades (50–950):

slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose

#![allow(unused)]
fn main() {
class="bg-blue-500 hover:bg-blue-600 text-gray-100 border-gray-300"
}

Special colors: bg-black, bg-white, bg-transparent, text-black, text-white, text-transparent, border-black, border-white, border-transparent.

Typography

Font weight: font-thin, font-light, font-normal, font-medium, font-semibold, font-bold, font-extrabold, font-black.

Font size: text-xs (12px), text-sm (14px), text-base (16px), text-lg (18px), text-xl (20px), text-2xl (24px), text-3xl (30px), text-4xl (36px), text-5xl (48px), text-6xl (60px), text-7xl (72px), text-8xl (96px), text-9xl (128px).

Text align: text-left, text-center, text-right.

Font family: font-mono, font-sans, font-serif.

Line height: leading-none, leading-tight (1.25), leading-normal (1.5), leading-loose (2.0).

Text decoration: underline, line-through, no-underline, decoration-solid, decoration-wavy, decoration-none, decoration-2 (thickness).

Text overflow: truncate (overflow hidden + nowrap + ellipsis), text-ellipsis, text-clip.

Font style: italic, not-italic.

White space: whitespace-normal, whitespace-nowrap.

Borders

Border width: border (1px all), border-t, border-r, border-b, border-l, border-t-N, border-r-N, border-b-N, border-l-N.

Border style: border-solid, border-dashed.

Border color: border-{color}-{shade}, border-[#hex].

Border radius

rounded (4px), rounded-sm (2px), rounded-md (6px), rounded-lg (8px), rounded-xl (12px), rounded-2xl (16px), rounded-3xl (24px), rounded-full (9999px), rounded-none (0px).

Per-corner: rounded-tl, rounded-tr, rounded-bl, rounded-br, rounded-t, rounded-r, rounded-b, rounded-l (with optional size suffix).

Shadows

shadow-sm, shadow, shadow-md, shadow-lg, shadow-xl, shadow-2xl, shadow-none.

Cursor

cursor-pointer, cursor-default, cursor-text, cursor-not-allowed, cursor-grab, cursor-grabbing, cursor-crosshair.

Opacity

opacity-0 through opacity-100 (in increments of 5).

Inset

inset-0, inset-auto, top-N, right-N, bottom-N, left-N.

Grid

grid-cols-N, grid-rows-N, col-N, row-N.

Aspect ratio

aspect-square (1.0), aspect-video (16/9), aspect-N/M (arbitrary ratio).

Line clamp

line-clamp-N (1–10).

Z-index

z-0, z-10, z-20, z-30, z-40, z-50, z-auto.