Utilities
The utility classes behind the elements: token colours, radius, breakpoints and sizes, with the usual layout and spacing classes.
On this page
Utilities are single-purpose classes for the one-off look: a margin, a colour, a grid. They come from UnoCSS, through the Wind preset the ui preset builds on, so the names are the familiar ones (flex, gap-4, p-3, text-sm, grid-cols-2, hidden). The preset changes only what ties them to the UI: colours, radius and breakpoints read the tokens, and each element's sizes are classes too.
Only what you use is built
The build scans the templates it is given and writes a rule for each class it finds, so the stylesheet holds only what the site uses. A class assembled in a template from pieces, like 'bg-' ~ $color, is never found. Write the whole name, or list the full names a template can produce.
Beating an element
The reset, the base and the element CSS sit in a layer before the utilities, and variants are written with :where(). A utility on an element therefore beats the element's own rule at the same specificity, with no !important:
{ui card, class: 'max-w-sm' /}
{ui button, title: 'Wide', class: 'w-full' /}
Colours
Every token is a colour. The fill is bg-{name}, text-{name}, border-{name} and the rest of the colour utilities. A pair names the text that sits on its fill, so text-primary-foreground goes on bg-primary. Because the tokens change with the theme, a utility written with them follows light, dark and any added theme, and there is no dark: variant to write.
Token colours
<div class="flex flex-wrap gap-2">
<div class="rounded-md bg-primary px-3 py-2 text-sm text-primary-foreground">primary</div>
<div class="rounded-md bg-raised px-3 py-2 text-sm text-foreground">raised</div>
<div class="rounded-md bg-sunken px-3 py-2 text-sm text-foreground">sunken</div>
<div class="rounded-md bg-hover px-3 py-2 text-sm text-foreground">hover</div>
<div class="rounded-md px-3 py-2 text-sm text-muted">muted</div>
<div class="rounded-md bg-destructive px-3 py-2 text-sm text-destructive-foreground">destructive</div>
<div class="rounded-md border border-border px-3 py-2 text-sm">border</div>
</div>
The names are background, foreground, card, primary, secondary, muted, accent, destructive, success, warning and info, each with a -foreground pair, plus border, input and ring. Theming shows them live.
Alpha
A slash sets the opacity of any colour utility. It is the way to get a soft tint from a status colour.
Alpha
<div class="flex flex-wrap gap-2">
<div class="rounded-md bg-primary/10 px-3 py-2 text-sm text-primary">bg-primary/10</div>
<div class="rounded-md bg-success/15 px-3 py-2 text-sm text-success">bg-success/15</div>
<div class="rounded-md bg-warning/15 px-3 py-2 text-sm text-warning">bg-warning/15</div>
<div class="rounded-md bg-info/15 px-3 py-2 text-sm text-info">bg-info/15</div>
<div class="rounded-md bg-destructive/15 px-3 py-2 text-sm text-destructive">bg-destructive/15</div>
</div>
Radius
rounded-lg is --radius, rounded-md is 2px less and rounded-sm is 4px less. Changing --radius in a theme moves all three, and every element that rounds with the token. rounded-full and rounded-none stay fixed.
Radius
<div class="flex flex-wrap gap-2">
<div class="border border-border px-3 py-2 text-sm rounded-sm">rounded-sm</div>
<div class="border border-border px-3 py-2 text-sm rounded-md">rounded-md</div>
<div class="border border-border px-3 py-2 text-sm rounded-lg">rounded-lg</div>
<div class="border border-border px-3 py-2 text-sm rounded-full">rounded-full</div>
</div>
Breakpoints
A prefix applies a utility from that width up: sm:grid-cols-2 is two columns at 640px and wider. One scale serves every prefix, and xxl takes the place of 2xl.
| Prefix | From |
|---|---|
xs: |
480px |
sm: |
640px |
md: |
768px |
lg: |
1024px |
xl: |
1280px |
xxl: |
1536px |
Start with the layout for the smallest screen and add prefixes as the space grows.
Columns by breakpoint
<div class="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-4">
<div class="rounded-md bg-sunken p-3 text-sm">One column</div>
<div class="rounded-md bg-sunken p-3 text-sm">Two from sm</div>
<div class="rounded-md bg-sunken p-3 text-sm">Four from lg</div>
<div class="rounded-md bg-sunken p-3 text-sm">Resize the window</div>
</div>
Layout and spacing
The rest are the standard utilities. A flex or grid container with a gap lays out its children, and elements nest inside them like any other tag.
Flex and gap
<div class="flex items-center justify-between gap-4 rounded-lg border border-border p-4">
<div class="flex flex-col gap-1">
<span class="font-semibold">Project</span>
<span class="text-sm text-muted">Updated today</span>
</div>
<div class="flex gap-2">
{ui badge, title: 'Active' /}
{ui button, title: 'Open', variant: 'outline' /}
</div>
</div>
Tags carry no margin of their own, so the base adds space above a block that follows another. Inside a container that sets a gap, put mt-0 on its blocks so the two do not add up.
Size classes
A size that changes by breakpoint is a class. Each element with sizes has {element}-{size} classes that take the same prefixes: lg:btn-lg is the large button from 1024px. The size param does the same without the prefix, so use the class only when the size depends on the screen.
| Class | Sizes |
|---|---|
btn-{size} |
sm, lg, icon |
avatar-{size} |
sm, lg |
spinner-{size} |
sm, lg |
status-{size} |
sm, lg |
modal-{size} |
sm, lg |
They are the variants and sizes rules from the overview, written as classes.
Prose
.prose is the one class of its own. Put it on a container of rendered markdown. It spaces and styles only the container's direct children, so a component placed among them keeps its own look:
<div class="prose">
{$html|noescape}
{ui alert, title: 'Heads up' /}
</div>