Tailwind Classes Reference
Complete reference for all Tailwind-style utility classes in Whitehall, with equivalent props and generated Kotlin/Compose output.
// Preferred: class syntax
<Column class="p-16 gap-8 items-center bg-primary rounded-lg">
<Text class="text-lg font-bold">Title</Text>
</Column>
// Also works: prop syntax (use for dynamic values)
<Column p={dynamicPadding} gap={8}>
<Text>Title</Text>
</Column> Scale: Classes and props use a 1:1 scale. The number IS the dp value: p-16 = p={16} = 16dp
Override: Props override class values: class="p-16" p={32} results in 32dp padding
bg-*, text-*, border-* and the rounded-* scale resolve against the project's tokens at runtime — so bg-card works, and theme="auto" repaints the app without a rebuild. Without one they fall through to
Material roles and the Tailwind palette, exactly as documented below.See it happen
Watch the chain change as classes are added.
<Box class="bg-primary"> <Text>Card</Text> </Box>
One class, one call: bg-primary becomes a single .background(...) on the Modifier chain.
Computed classes
A literal class string is compiled. A computed one is looked up on the phone instead:
<Text class={selected ? "font-bold" : "text-muted-foreground"}>{row.name}</Text> The lookup runs against a table generated from every class the project writes anywhere, so
it costs nothing at runtime beyond the lookup itself. A handful of classes need more than
that table can give them — the element's parent, or the whole tree — and can only be
written in a literal class="…":
flex-1,flex-growandself-*— need the parent's scopesafeand itssafe-*edges — need the whole treebackdrop-blur-*— needs what is painted behind the element- an image background (
bg-[url(…)],background=) — resolved at build time - a per-side
rounded-tl-*and friends — the baserounded-*scale computes fine
Naming one of these inside class={…} is a build error, class-not-computable, at the line that wrote it — not a class silently dropped
on the phone.
Array form
class={[base, sizes[size], extra]} is Svelte's array form: the parts
are joined with a space.
States
<Row class="h-36 px-10 bg-primary transition-all active:bg-primary/80 disabled:opacity-50 dark:bg-input/30"
disabled={busy} onClick={save}> A class can wait for a state. active: (and hover:, which on a touch
screen is the same press) applies while the element is held down, disabled: while its disabled is true, and dark: under the dark scheme.
Prefixes combine (dark:active:bg-input/50), and the more specific class wins.
An element with a pressed class draws no ripple, and its disabled refuses the
click. transition-all eases every change over 150ms. Any other prefix is a
build error that names these four.
Text classes on a container
<Column class="text-sm font-medium text-muted-foreground">
<Text>Takes the container's text classes</Text>
<Text class="text-foreground">Its own class wins</Text>
</Column> Text classes on a container reach every text inside it, as CSS inherits them. A text's own class wins.
Icons, translation and capped radius
<Row class="[&_svg]:size-16"><Icon name="lucide:plus" /></Row>
<Box class="translate-y-1"></Box>
<Box class="rounded-[min(var(--radius-md),8px)]"></Box> [&_svg]:size-16 sizes the icons inside a container. translate-y-1 (and translate-x-N, with a leading - for the
other direction) moves an element without resizing it; the number is dp. rounded-[min(var(--radius-md),8px)] is the project's radius step, capped: the cap
binds only when the project's radius is large.
Spacing
Padding
| Class | Prop | Compose Output |
|---|---|---|
p-{n} | p={n} | .padding(n.dp) |
px-{n} | px={n} | .padding(horizontal = n.dp) |
py-{n} | py={n} | .padding(vertical = n.dp) |
pt-{n} | pt={n} | .padding(top = n.dp) |
pb-{n} | pb={n} | .padding(bottom = n.dp) |
ps-{n} | ps={n} | .padding(start = n.dp) |
pe-{n} | pe={n} | .padding(end = n.dp) |
<Column class="p-16"> // 16dp all sides
<Column class="px-16 py-8"> // 16dp horizontal, 8dp vertical
<Column class="pt-32 pb-16"> // 32dp top, 16dp bottom Margin
Same pattern as padding (Compose uses outer padding for margin):
| Class | Prop | Compose Output |
|---|---|---|
m-{n} | m={n} | .padding(n.dp) |
mx-{n}, my-{n}, etc. | mx={n}, etc. | Same pattern as padding |
Gap
| Class | Prop | Compose Output |
|---|---|---|
gap-{n} | gap={n} | Arrangement.spacedBy(n.dp) |
<Column class="gap-16"> // 16dp between children
<Row class="gap-8"> // 8dp between children Sizing
Width
| Class | Prop | Compose Output |
|---|---|---|
w-{n} | w={n} | .width(n.dp) |
w-full | width="100%" | .fillMaxWidth() |
w-1/2 | width="50%" | .fillMaxWidth(0.5f) |
w-1/3 | width="33%" | .fillMaxWidth(0.333f) |
w-2/3 | width="67%" | .fillMaxWidth(0.667f) |
w-fit | — | .wrapContentWidth(Alignment.Start) |
w-fit is CSS's fit-content: as wide as the content, never wider
than the room there is. Where a parent forces a width on the element, it keeps its content
width and sits at the start.
Height
| Class | Prop | Compose Output |
|---|---|---|
h-{n} | h={n} | .height(n.dp) |
h-full | height="100%" | .fillMaxHeight() |
h-1/2 | height="50%" | .fillMaxHeight(0.5f) |
h-fit | — | .wrapContentHeight(Alignment.Top) |
Size (Both)
| Class | Prop | Compose Output |
|---|---|---|
size-{n} | size={n} | .size(n.dp) |
<Box class="w-full h-64"> // Full width, 64dp height
<Box class="w-1/2"> // 50% width
<Box class="size-48"> // 48dp x 48dp Layout (Flex)
Cross-axis Alignment (items)
| Class | Column | Row |
|---|---|---|
items-start | Alignment.Start | Alignment.Top |
items-center | Alignment.CenterHorizontally | Alignment.CenterVertically |
items-end | Alignment.End | Alignment.Bottom |
Main-axis Arrangement (justify)
| Class | Compose Output |
|---|---|
justify-start | Arrangement.Start |
justify-center | Arrangement.Center |
justify-end | Arrangement.End |
justify-between | Arrangement.SpaceBetween |
justify-around | Arrangement.SpaceAround |
justify-evenly | Arrangement.SpaceEvenly |
Weight
| Class | Compose Output |
|---|---|
flex-1 | .weight(1f) |
flex-grow | .weight(1f) |
<Column class="items-center justify-between">
<Row class="items-center gap-8">
<Box class="flex-1"> Scrollable
| Class | Prop | Compose Output |
|---|---|---|
overflow-scroll | scrollable | .verticalScroll(rememberScrollState()) (Column) |
overflow-y-scroll | scrollable="vertical" | .verticalScroll(rememberScrollState()) |
overflow-x-scroll | scrollable="horizontal" | .horizontalScroll(rememberScrollState()) |
<Column class="overflow-scroll p-16">
<Text>Scrollable content...</Text>
</Column>
<Row scrollable>
<Image src="1.jpg" />
<Image src="2.jpg" />
</Row> Background
Semantic colors
Colors named for the job they do rather than the hue they are. These work under every preset, and they are what to reach for when a color should follow the app's theme instead of being pinned to a value.
| Name | What it is |
|---|---|
background / foreground | The page, and text on it |
card / card-foreground | A raised surface, and text on it |
popover / popover-foreground | A floating surface, and text on it |
primary / primary-foreground | The main action, and text on it |
secondary / secondary-foreground | A quieter action, and text on it |
muted / muted-foreground | A recessed fill, and secondary text |
accent / accent-foreground | A hover or active fill, and text on it |
destructive / destructive-foreground | Danger, and text on it |
border | A divider or an outline |
input | A field's edge, a step stronger than a border |
ring | A focus ring |
Each takes the usual prefixes, and the usual opacity suffix:
<Column class="bg-background">
<Card class="bg-card border border-border">
<Text class="text-card-foreground">Title</Text>
<Text class="text-muted-foreground">Subtitle</Text>
<Button class="bg-destructive text-destructive-foreground">Delete</Button>
</Card>
</Column> Theme Colors
| Class | Compose Output |
|---|---|
bg-primary | .background(MaterialTheme.colorScheme.primary) |
bg-secondary | .background(MaterialTheme.colorScheme.secondary) |
bg-surface | .background(MaterialTheme.colorScheme.surface) |
bg-error | .background(MaterialTheme.colorScheme.error) |
bg-transparent | .background(Color.Transparent) |
bg-white | .background(Color.White) |
bg-black | .background(Color.Black) |
Hex Colors
| Class | Compose Output |
|---|---|
bg-[#RRGGBB] | .background(Color(0xFFRRGGBB)) |
Tailwind Palette Colors
Full Tailwind color palette with shades 50-950:
| Class | Hex Value | Compose Output |
|---|---|---|
bg-yellow | #EAB308 (yellow-500) | .background(Color(0xFFEAB308)) |
bg-yellow-100 | #FEF9C3 | .background(Color(0xFFFEF9C3)) |
bg-yellow-500 | #EAB308 | .background(Color(0xFFEAB308)) |
bg-yellow-900 | #713F12 | .background(Color(0xFF713F12)) |
bg-blue-500 | #3B82F6 | .background(Color(0xFF3B82F6)) |
bg-red-500 | #EF4444 | .background(Color(0xFFEF4444)) |
bg-green-500 | #22C55E | .background(Color(0xFF22C55E)) |
Available colors: slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose
Available shades: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950
Opacity Modifier
Use /N suffix (0-100) to apply alpha transparency:
| Class | Compose Output |
|---|---|
bg-red-500/20 | .background(Color(0x33EF4444)) |
bg-blue/50 | .background(Color(0x803B82F6)) |
bg-white/80 | .background(Color(0xCCFFFFFF)) |
bg-black/10 | .background(Color(0x1A000000)) |
bg-primary/50 | .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.5f)) |
<Box class="bg-primary">
<Box class="bg-[#FF5722]">
<Box class="bg-yellow"> // yellow-500
<Box class="bg-yellow-100"> // light yellow
<Box class="bg-red-500/20"> // red at 20% opacity Gradients
| Class | Purpose |
|---|---|
bg-gradient-to-r, -l, -t, -b | Linear gradient along an axis |
bg-gradient-to-tr, -tl, -br, -bl | Linear gradient along a diagonal |
from-{color} | First stop |
via-{color} | Optional middle stop |
to-{color} | Last stop |
Compiles to Brush.linearGradient(...), with the direction suffix mapped to Offsets. Stop colors use the same grammar as bg-* — theme tokens,
Material roles, the Tailwind palette, arbitrary hex — each with the same /opacity suffix. A missing from-*/to-* stop defaults to
transparent, matching Tailwind. bg-gradient-to-* wins over a plain bg-* on the same element, the way a CSS background-image layers over
a background-color.
<Box class="bg-gradient-to-r from-blue-500 to-purple-500">
<Box class="bg-gradient-to-br from-yellow-400 via-orange-500 to-red-500">
<Card class="bg-gradient-to-b from-primary to-secondary"> Background images
A background can be an image as well as a color or a gradient. The image itself is one
value; everything about how it is drawn is its own class, the way Tailwind splits CSS's
shorthand. Write the image as a class or as a prop — both resolve the path against static/ at build time:
<Box class="w-full h-full bg-[url(/backgrounds/city.jpg)] bg-cover bg-center" />
<Box background="url(/backgrounds/city.jpg)" class="bg-cover bg-center" /> | Class | Controls |
|---|---|
bg-cover bg-contain bg-auto bg-[85%] | How much of the source is sampled |
bg-center bg-top bg-bottom-right bg-[30%_40%] | Where the sampled rect sits |
bg-repeat bg-no-repeat bg-repeat-x bg-repeat-y | Tiling |
bg-fixed bg-local | Positioned against the window, or against the element |
Paths resolve against static/ at build time. backgroundPositionX and backgroundPositionY are morphable, which is how a background parallaxes against a
scroll.
url(…) — resolved at build time, and a
background has nowhere to put a loading state, so put an <Image> under the
content instead — and an absolute bg-[300px] size.Blur, Blend and Clipping
blur-*
Blurs the element's own content — its fill, its border, anything inside it. Tailwind's names and Tailwind's values.
| Class | Radius |
|---|---|
blur-xs blur-sm blur-md blur-lg | 4 / 8 / 12 / 16 dp |
blur-xl blur-2xl blur-3xl | 24 / 40 / 64 dp |
blur | 8 dp — Tailwind v3's default, kept as an alias |
blur-none | Emits nothing |
blur-[17] blur-[17px] | 17 dp |
Like CSS's filter: blur(), it spreads outside the element's box. A rounded-* or overflow-hidden on the same element clips it back,
exactly as overflow: hidden does on the web.
backdrop-blur-*
Blurs what is painted behind the element — a frosted panel over a photo or a scrolling list. Same scale, same names.
<Box class="w-full h-full">
<Image src="/backgrounds/city.jpg" fit="cover" class="w-full h-full" />
<Box class="backdrop-blur-xl bg-white/20 rounded-3xl p-32">
<Text class="text-5xl">Blur!</Text>
</Box>
</Box> Nothing marks the content being sampled. The compiler works out what to blur: everything painted below the element in the same markup tree — preceding siblings at every level up the chain, which is CSS's own definition of a backdrop.
- Put the class where the backdrop is visible. A component whose own root
says
backdrop-blur-xlwith nothing behind it in its own file is a build error. Pass the class at the use site instead —<FrostedCard class="backdrop-blur-xl" />. - Name a pair when a screen has more than one, or to bound what gets
recorded:
backdrop/photoon the source,backdrop-blur-xl/photoon the panel. Tailwind'sgroup/editspelling. - A child does not sample its own parent — recording an ancestor would record the consumer inside it. Put a background meant to be blurred beside the panel, not around it.
mix-blend-*
Blends the element with what is beneath it. Seventeen of Tailwind's eighteen names, mapped to
Compose's BlendMode.
<Box class="mix-blend-plus-lighter" background="color(srgb-extended 2 2 2)" />
<Box class="mix-blend-soft-light bg-black/12" /> The lowering is picked per element: a fill with no children blends straight into the parent's canvas — one draw, no buffer — and anything else gets an offscreen layer, which is unavoidable, since you cannot blend a composite that does not exist yet.
mix-blend-plus-darker has no Compose equivalent and is a build error rather than
a silent no-op. And mix-blend-* on an element that something below it blurs is
refused: being recorded gives it a canvas of its own, so the blend would quietly do nothing.overflow-hidden
Clips children to the element's bounds, including a blur-* that would otherwise
spread past them. Pairs with rounded-* to clip to the corner radius.
<Box class="overflow-hidden rounded-2xl">
<Image src={url} fit="cover" />
</Box> Border Radius
| Class | dp Value | Compose Output |
|---|---|---|
rounded-none | 0dp | RoundedCornerShape(0.dp) |
rounded-sm | 2dp | RoundedCornerShape(2.dp) |
rounded | 4dp | RoundedCornerShape(4.dp) |
rounded-md | 6dp | RoundedCornerShape(6.dp) |
rounded-lg | 8dp | RoundedCornerShape(8.dp) |
rounded-xl | 12dp | RoundedCornerShape(12.dp) |
rounded-2xl | 16dp | RoundedCornerShape(16.dp) |
rounded-3xl | 24dp | RoundedCornerShape(24.dp) |
rounded-4xl | radius × 2.6 | the project's radius times 2.6 (26dp at the default radius); not rounded-full |
rounded-full | Circle | CircleShape |
Side-specific
| Class | Description |
|---|---|
rounded-t-{size} | Top corners only |
rounded-b-{size} | Bottom corners only |
rounded-s-{size} | Start corners only |
rounded-e-{size} | End corners only |
<Card class="rounded-lg">
<Box class="rounded-full">
<Card class="rounded-t-xl"> preset = "none". With a shadcn theme, rounded-sm through rounded-xl scale with the project's own --radius instead — see Theming.Border
Border Width
| Class | Compose Output |
|---|---|
border | .border((1f / density).dp, ...) |
border-0 | No border |
border-2 | .border(2.dp, ...) |
border-4 | .border(4.dp, ...) |
A bare border is Tailwind's own default weight, 1 px — one physical
pixel, not a flat 1.dp. At a fractional density (2.625× on the reference device) a
flat 1.dp line rounds up to 3 physical pixels, nearly three times the hairline the
browser renders. (1f / density).dp converts back to exactly one physical pixel
whatever the density is. Every other width is a literal dp value; the overshoot is only
dramatic at 1px.
Directional Borders
| Class | Effect |
|---|---|
border-t | Top edge only, one physical pixel |
border-b | Bottom edge only, one physical pixel |
border-l | Left edge only, one physical pixel |
border-r | Right edge only, one physical pixel |
border-x | Left and right edges |
border-y | Top and bottom edges |
border-t-2, border-b-4, … | Any edge with an explicit dp width |
There is no per-edge Modifier.border in Compose, so a directional border compiles
to a drawBehind that strokes only the requested edges. The border reserves its own space, the way a border-box edge adds to a content-sized
element's height on the web: each active edge also gets a .padding() (for t/b) or .absolutePadding() (for l/r)
— absolute, not start/end, because Tailwind's l/r are the physical sides, not the logical ones ps-/pe- already claim.
<Box class="border-b p-16"> // hairline bottom rule
<Row class="border-t-2 border-primary"> // 2dp top rule, theme color
<Column class="border-x-4"> // 4dp on both left and right Border Style
| Class | Draws |
|---|---|
border-solid | the default, spelled out |
border-dashed | dashes and gaps three widths long |
border-dotted | round dots, one width across and one width apart |
<Box class="h-120 rounded-md border border-dashed"> // a drop zone
<Row class="border-b-2 border-dotted"> // a dotted rule A dashed or dotted border is the element's own outline, its rounded-* shape
included, stroked inside the edge. On a directional edge the pattern goes on that edge.
Border Colors
| Class | Compose Output |
|---|---|
border-primary | .border(..., MaterialTheme.colorScheme.primary) |
border-outline | .border(..., MaterialTheme.colorScheme.outline) |
border-white | .border(..., Color.White) |
border-black | .border(..., Color.Black) |
border-yellow | .border(..., Color(0xFFEAB308)) |
border-blue-300 | .border(..., Color(0xFF93C5FD)) |
border-black/10 | .border(..., Color(0x1A000000)) |
Edges share whatever border-{color} sets (or MaterialTheme.colorScheme.outline by default). There is no per-edge color —
Tailwind's border-t-red-500 has no equivalent here.
<Box class="border-2 border-primary rounded-lg">
<Box class="border border-yellow-300 rounded">
<Box class="border border-black/10"> // subtle border Shadow & Opacity
Shadow
With a theme, shadow-* is Tailwind's real box shadow — offset, blur, spread and
color, most steps stacking two layers. Without one it stays the Material elevation it always
was, so nothing that predates themes changes.
| Class | CSS (Tailwind v4) | Elevation under preset = "none" |
|---|---|---|
shadow-none | none | No shadow |
shadow-2xs | 0 1px rgb(0 0 0 / 0.05) | No shadow |
shadow-xs | 0 1px 2px 0 rgb(0 0 0 / 0.05) | 2dp |
shadow-sm | 0 1px 3px 0 …, 0 1px 2px -1px … | 2dp |
shadow | Tailwind v3's shadow, which v4 renamed shadow-sm | 4dp |
shadow-md | 0 4px 6px -1px …, 0 2px 4px -2px … | 6dp |
shadow-lg | 0 10px 15px -3px …, 0 4px 6px -4px … | 10dp |
shadow-xl | 0 20px 25px -5px …, 0 8px 10px -6px … | 16dp |
shadow-2xl | 0 25px 50px -12px rgb(0 0 0 / 0.25) | 24dp |
shadow-lg is not "10dp of elevation" — it
is two specific shadows. Compose 1.9's Modifier.dropShadow takes exactly CSS's
parameters, so the scale is carried across as written rather than approximated.The bare shadow keeps pointing at the same visual weight it always had, so
existing projects do not silently change when v4 shifted the whole scale down a step.
Ring
| Class | Draws |
|---|---|
ring, ring-1 | a one-physical-pixel ring |
ring-{n} | an ndp ring |
ring-0 | no ring |
ring-{color}, ring-{color}/{opacity} | the ring's color, same grammar as border-{color} |
<Column class="rounded-lg ring-1 ring-foreground/10"> // shadcn's card edge A ring is a spread with no blur, drawn outside the border box, following its rounded-* radius and taking no layout space. With no color class it is the
current content color. Without a theme a ring falls back to a .border of the
same width inside the edge.
Opacity
| Class | Alpha | Compose Output |
|---|---|---|
opacity-0 | 0% | .alpha(0f) |
opacity-25 | 25% | .alpha(0.25f) |
opacity-50 | 50% | .alpha(0.5f) |
opacity-75 | 75% | .alpha(0.75f) |
opacity-100 | 100% | .alpha(1f) |
<Card class="shadow-lg opacity-75"> Safe Area
Handle system UI insets (status bar, navigation bar):
| Class | Prop | Compose Output |
|---|---|---|
safe | safeArea | .windowInsetsPadding(WindowInsets.systemBars) |
safe-top | safeTop | .windowInsetsPadding(WindowInsets.statusBars) |
safe-bottom | safeBottom | .windowInsetsPadding(WindowInsets.navigationBars) |
<Column class="safe-top p-16"> // Avoid status bar overlap
<Column class="safe"> // Avoid both bars
<Column safeTop safeBottom> // Prop syntax Typography
Font Size
| Class | sp Value | Compose Output |
|---|---|---|
text-xs | 12sp | fontSize = 12.sp |
text-sm | 14sp | fontSize = 14.sp |
text-base | 16sp | fontSize = 16.sp |
text-lg | 18sp | fontSize = 18.sp |
text-xl | 20sp | fontSize = 20.sp |
text-2xl | 24sp | fontSize = 24.sp |
text-3xl | 30sp | fontSize = 30.sp |
text-4xl | 36sp | fontSize = 36.sp |
text-11 | 11sp | fontSize = 11.sp |
A bare number is the size itself: text-11 is 11sp, the same way px-12 is 12dp. The spacing scale here is the identity function — a phone
layout is specified in dp and you are holding a dp number in your head — so a number
means what it says everywhere a size goes, rounded-12 included.
A named step carries a line height as well as a size (text-sm is 14sp and a 20sp line box, as Tailwind pairs them). A bare number is a size and
nothing else.
Font Weight
| Class | Compose Output |
|---|---|
font-thin | FontWeight.Thin |
font-light | FontWeight.Light |
font-normal | FontWeight.Normal |
font-medium | FontWeight.Medium |
font-semibold | FontWeight.SemiBold |
font-bold | FontWeight.Bold |
font-extrabold | FontWeight.ExtraBold |
font-black | FontWeight.Black |
All nine weights are declared against the theme font's wght axis, so font-bold gets the typeface's real bold rather than a synthesized smear of the
Regular master.
Font Family
| Class | Compose Output |
|---|---|
font-mono | fontFamily = FontFamily.Monospace |
FontFamily.Monospace is a Compose constant, not a project setting — the font key in Theming configures the body typeface, which is a different axis, so font-mono does not go through the theme
layer. font-sans stays unmapped: in Tailwind it undoes a browser default Compose
never had.
Letter Spacing
| Class | Value |
|---|---|
tracking-tighter | -0.05em |
tracking-tight | -0.025em |
tracking-normal | 0em |
tracking-wide | 0.025em |
tracking-wider | 0.05em |
tracking-widest | 0.1em |
Tailwind's scale is in em, which maps directly onto Compose's TextStyle.letterSpacing. tracking-normal is an explicit 0em, not "unset" — Material's bodyLarge otherwise leaks letterSpacing = 0.5sp into every <Text>.
<Text class="text-xs tracking-wide font-medium">Section Label</Text> Font Style & Decoration
| Class | Compose Output |
|---|---|
italic | FontStyle.Italic |
not-italic | FontStyle.Normal |
underline | TextDecoration.Underline |
line-through | TextDecoration.LineThrough |
no-underline | TextDecoration.None |
tabular-nums | fontFeatureSettings = "tnum" |
proportional-nums | fontFeatureSettings = "pnum" |
uppercase | text.uppercase() |
lowercase | text.lowercase() |
capitalize | text.replaceFirstChar { it.uppercase() } |
tabular-nums asks the font for fixed-width digits. Reach for it on any number
that changes while someone is looking at it — a clock, a value under a dragging thumb,
a countdown: a 1 is narrower than a 0 in a proportional face, so
the readout shifts sideways on every tick without it.
The case classes change what is drawn, not what is stored, which is what CSS's text-transform does — so write the label the way a translator should read it.
Line Height (Leading)
| Class | Line Height | Description |
|---|---|---|
leading-none | 1em | No extra spacing |
leading-tight | 1.25em | Tight spacing |
leading-snug | 1.375em | Snug spacing |
leading-normal | 1.5em | Normal spacing (default) |
leading-relaxed | 1.625em | Relaxed spacing |
leading-loose | 2em | Double spacing |
leading-{n} | n.sp | Fixed sp value |
Text Alignment
| Class | Compose Output |
|---|---|
text-left | TextAlign.Start |
text-center | TextAlign.Center |
text-right | TextAlign.End |
text-justify | TextAlign.Justify |
Text Color
| Class | Compose Output |
|---|---|
text-primary | MaterialTheme.colorScheme.primary |
text-secondary | MaterialTheme.colorScheme.secondary |
text-white | Color.White |
text-black | Color.Black |
text-[#RRGGBB] | Color(0xFFRRGGBB) |
text-yellow | Color(0xFFEAB308) |
text-blue-900 | Color(0xFF1E3A8A) |
text-white/80 | Color(0xCCFFFFFF) |
Text Overflow
| Class | Compose Output |
|---|---|
truncate | overflow = TextOverflow.Ellipsis, maxLines = 1 |
line-clamp-{n} | maxLines = n |
<Text class="text-lg font-bold text-primary">Title</Text>
<Text class="text-sm italic text-center">Subtitle</Text>
<Text class="truncate">Long text that gets cut off...</Text>
<Text class="line-clamp-2">Text limited to 2 lines...</Text>
<Text class="text-lg leading-relaxed">Comfortable reading</Text> Complete Example
<Column class="p-16 gap-16 bg-surface">
<Text class="text-2xl font-bold text-primary">Welcome</Text>
<Card class="p-16 rounded-lg shadow-md">
<Column class="gap-8">
<Text class="text-lg font-medium">Card Title</Text>
<Text class="text-sm text-secondary line-clamp-2">
Description text that might be long...
</Text>
</Column>
</Card>
<Row class="gap-8 items-center justify-between">
<Button class="flex-1">Cancel</Button>
<Button class="flex-1 bg-primary">Submit</Button>
</Row>
</Column> See Also
- Theming - Where
bg-cardand the rounded-* scale come from - Components - The shadcn component library
- Layout Components - Column, Row, Box
- Text Component - Text styling details
- Transitions - Page and element transitions
- Morph Drivers - Progress-driven animations