Documentation

Tailwind Classes Reference

Complete reference for all Tailwind-style utility classes in Whitehall, with equivalent props and generated Kotlin/Compose output.

Prefer classes over props. Classes are faster to write, more scannable, and consistent with web conventions. A computed class list works too — see Computed classes below for the few that don't.
// 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

Color classes read the theme. With a theme preset, 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.

Card.wh
<Box class="bg-primary">
  <Text>Card</Text>
</Box>
Kotlin waiting
Scroll into view to compile.

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-grow and self-* — need the parent's scope
  • safe and its safe-* edges — need the whole tree
  • backdrop-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 base rounded-* 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

ClassPropCompose 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):

ClassPropCompose Output
m-{n}m={n}.padding(n.dp)
mx-{n}, my-{n}, etc.mx={n}, etc.Same pattern as padding

Gap

ClassPropCompose 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

ClassPropCompose Output
w-{n}w={n}.width(n.dp)
w-fullwidth="100%".fillMaxWidth()
w-1/2width="50%".fillMaxWidth(0.5f)
w-1/3width="33%".fillMaxWidth(0.333f)
w-2/3width="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

ClassPropCompose Output
h-{n}h={n}.height(n.dp)
h-fullheight="100%".fillMaxHeight()
h-1/2height="50%".fillMaxHeight(0.5f)
h-fit—.wrapContentHeight(Alignment.Top)

Size (Both)

ClassPropCompose 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)

ClassColumnRow
items-startAlignment.StartAlignment.Top
items-centerAlignment.CenterHorizontallyAlignment.CenterVertically
items-endAlignment.EndAlignment.Bottom

Main-axis Arrangement (justify)

ClassCompose Output
justify-startArrangement.Start
justify-centerArrangement.Center
justify-endArrangement.End
justify-betweenArrangement.SpaceBetween
justify-aroundArrangement.SpaceAround
justify-evenlyArrangement.SpaceEvenly

Weight

ClassCompose 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

ClassPropCompose Output
overflow-scrollscrollable.verticalScroll(rememberScrollState()) (Column)
overflow-y-scrollscrollable="vertical".verticalScroll(rememberScrollState())
overflow-x-scrollscrollable="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.

NameWhat it is
background / foregroundThe page, and text on it
card / card-foregroundA raised surface, and text on it
popover / popover-foregroundA floating surface, and text on it
primary / primary-foregroundThe main action, and text on it
secondary / secondary-foregroundA quieter action, and text on it
muted / muted-foregroundA recessed fill, and secondary text
accent / accent-foregroundA hover or active fill, and text on it
destructive / destructive-foregroundDanger, and text on it
borderA divider or an outline
inputA field's edge, a step stronger than a border
ringA 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

ClassCompose 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

ClassCompose Output
bg-[#RRGGBB].background(Color(0xFFRRGGBB))

Tailwind Palette Colors

Full Tailwind color palette with shades 50-950:

ClassHex ValueCompose 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:

ClassCompose 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

ClassPurpose
bg-gradient-to-r, -l, -t, -bLinear gradient along an axis
bg-gradient-to-tr, -tl, -br, -blLinear 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" />
ClassControls
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-yTiling
bg-fixed bg-localPositioned 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.

Not supported: a remote 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.

ClassRadius
blur-xs blur-sm blur-md blur-lg4 / 8 / 12 / 16 dp
blur-xl blur-2xl blur-3xl24 / 40 / 64 dp
blur8 dp — Tailwind v3's default, kept as an alias
blur-noneEmits 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-xl with 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/photo on the source, backdrop-blur-xl/photo on the panel. Tailwind's group/edit spelling.
  • 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

Classdp ValueCompose Output
rounded-none0dpRoundedCornerShape(0.dp)
rounded-sm2dpRoundedCornerShape(2.dp)
rounded4dpRoundedCornerShape(4.dp)
rounded-md6dpRoundedCornerShape(6.dp)
rounded-lg8dpRoundedCornerShape(8.dp)
rounded-xl12dpRoundedCornerShape(12.dp)
rounded-2xl16dpRoundedCornerShape(16.dp)
rounded-3xl24dpRoundedCornerShape(24.dp)
rounded-4xlradius × 2.6the project's radius times 2.6 (26dp at the default radius); not rounded-full
rounded-fullCircleCircleShape

Side-specific

ClassDescription
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">
These are the values under preset = "none". With a shadcn theme, rounded-sm through rounded-xl scale with the project's own --radius instead — see Theming.

Border

Border Width

ClassCompose Output
border.border((1f / density).dp, ...)
border-0No 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

ClassEffect
border-tTop edge only, one physical pixel
border-bBottom edge only, one physical pixel
border-lLeft edge only, one physical pixel
border-rRight edge only, one physical pixel
border-xLeft and right edges
border-yTop 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

ClassDraws
border-solidthe default, spelled out
border-dasheddashes and gaps three widths long
border-dottedround 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

ClassCompose 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.

ClassCSS (Tailwind v4)Elevation under preset = "none"
shadow-nonenoneNo shadow
shadow-2xs0 1px rgb(0 0 0 / 0.05)No shadow
shadow-xs0 1px 2px 0 rgb(0 0 0 / 0.05)2dp
shadow-sm0 1px 3px 0 …, 0 1px 2px -1px …2dp
shadowTailwind v3's shadow, which v4 renamed shadow-sm4dp
shadow-md0 4px 6px -1px …, 0 2px 4px -2px …6dp
shadow-lg0 10px 15px -3px …, 0 4px 6px -4px …10dp
shadow-xl0 20px 25px -5px …, 0 8px 10px -6px …16dp
shadow-2xl0 25px 50px -12px rgb(0 0 0 / 0.25)24dp
Elevation and box shadow do not convert. Android's shadow is a height: you give it a number and the platform derives blur and offset from a fixed light position. CSS gives you the shadow directly, and Tailwind's scale uses all four parameters including negative spread. 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

ClassDraws
ring, ring-1a one-physical-pixel ring
ring-{n}an ndp ring
ring-0no 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

ClassAlphaCompose Output
opacity-00%.alpha(0f)
opacity-2525%.alpha(0.25f)
opacity-5050%.alpha(0.5f)
opacity-7575%.alpha(0.75f)
opacity-100100%.alpha(1f)
<Card class="shadow-lg opacity-75">

Safe Area

Handle system UI insets (status bar, navigation bar):

ClassPropCompose Output
safesafeArea.windowInsetsPadding(WindowInsets.systemBars)
safe-topsafeTop.windowInsetsPadding(WindowInsets.statusBars)
safe-bottomsafeBottom.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

Classsp ValueCompose Output
text-xs12spfontSize = 12.sp
text-sm14spfontSize = 14.sp
text-base16spfontSize = 16.sp
text-lg18spfontSize = 18.sp
text-xl20spfontSize = 20.sp
text-2xl24spfontSize = 24.sp
text-3xl30spfontSize = 30.sp
text-4xl36spfontSize = 36.sp
text-1111spfontSize = 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

ClassCompose Output
font-thinFontWeight.Thin
font-lightFontWeight.Light
font-normalFontWeight.Normal
font-mediumFontWeight.Medium
font-semiboldFontWeight.SemiBold
font-boldFontWeight.Bold
font-extraboldFontWeight.ExtraBold
font-blackFontWeight.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

ClassCompose Output
font-monofontFamily = 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

ClassValue
tracking-tighter-0.05em
tracking-tight-0.025em
tracking-normal0em
tracking-wide0.025em
tracking-wider0.05em
tracking-widest0.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

ClassCompose Output
italicFontStyle.Italic
not-italicFontStyle.Normal
underlineTextDecoration.Underline
line-throughTextDecoration.LineThrough
no-underlineTextDecoration.None
tabular-numsfontFeatureSettings = "tnum"
proportional-numsfontFeatureSettings = "pnum"
uppercasetext.uppercase()
lowercasetext.lowercase()
capitalizetext.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)

ClassLine HeightDescription
leading-none1emNo extra spacing
leading-tight1.25emTight spacing
leading-snug1.375emSnug spacing
leading-normal1.5emNormal spacing (default)
leading-relaxed1.625emRelaxed spacing
leading-loose2emDouble spacing
leading-{n}n.spFixed sp value

Text Alignment

ClassCompose Output
text-leftTextAlign.Start
text-centerTextAlign.Center
text-rightTextAlign.End
text-justifyTextAlign.Justify

Text Color

ClassCompose Output
text-primaryMaterialTheme.colorScheme.primary
text-secondaryMaterialTheme.colorScheme.secondary
text-whiteColor.White
text-blackColor.Black
text-[#RRGGBB]Color(0xFFRRGGBB)
text-yellowColor(0xFFEAB308)
text-blue-900Color(0xFF1E3A8A)
text-white/80Color(0xCCFFFFFF)

Text Overflow

ClassCompose Output
truncateoverflow = 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