Tailwind in a design
The Tailwind CSS v4 classes and theme of a design.
Knighn designs use Tailwind CSS v4. The file renders with the Tailwind browser build, and the editor uses the same compiler. Classes are the stored truth: the properties panel reads them and writes them. Write classes the way that a careful developer writes them.
Spacing
One spacing step is 4 px. The step number is the size divided by 4.
| Class | Size | Class | Size | Class | Size |
|---|---|---|---|---|---|
p-px |
1 px | p-4 |
16 px | p-16 |
64 px |
p-0.5 |
2 px | p-5 |
20 px | p-20 |
80 px |
p-1 |
4 px | p-6 |
24 px | p-24 |
96 px |
p-1.5 |
6 px | p-8 |
32 px | p-32 |
128 px |
p-2 |
8 px | p-10 |
40 px | p-40 |
160 px |
p-3 |
12 px | p-12 |
48 px | p-64 |
256 px |
- The same steps work for
m-*,gap-*,w-*,h-*,size-*,inset-*,space-*andleading-*. - Tailwind v4 accepts each whole step, not only the steps in the table:
w-90is 360 px, andh-13is 52 px. - Keep to a rhythm: 4, 8, 12, 16, 24, 32, 48, 64, 96. Use gaps of 8 to 16 in a component, 24 to 48 between groups and 64 to 128 between sections.
Type
| Class | Size | Line height |
|---|---|---|
text-xs |
12 px | 16 px |
text-sm |
14 px | 20 px |
text-base |
16 px | 24 px |
text-lg |
18 px | 28 px |
text-xl |
20 px | 28 px |
text-2xl |
24 px | 32 px |
text-3xl |
30 px | 36 px |
text-4xl |
36 px | 40 px |
text-5xl |
48 px | 1 |
text-6xl |
60 px | 1 |
text-7xl |
72 px | 1 |
text-8xl |
96 px | 1 |
- Weights:
font-normal400,font-medium500,font-semibold600,font-bold700. - Line height:
leading-none1,leading-tight1.25,leading-snug1.375,leading-normal1.5,leading-relaxed1.625. A step also works:leading-7is 28 px.text-lg/7sets the size and the line height together. - Letter spacing:
tracking-tighter-0.05em,tracking-tight-0.025em,tracking-wide0.025em,tracking-wider0.05em,tracking-widest0.1em. - For headings, use
tracking-tightandtext-balance. For paragraphs, usetext-prettyand a measure of 60 to 75 characters:max-w-proseormax-w-xl. - Body text is 16 px on desktop and mobile. Secondary text is 14 px. Do not use text smaller than 12 px.
Radius, shadow and colour
- Radius:
rounded-xs2 px,rounded-sm4 px,rounded-md6 px,rounded-lg8 px,rounded-xl12 px,rounded-2xl16 px,rounded-3xl24 px,rounded-full. A style can changesmtoxlwith tokens. - Shadow:
shadow-2xs,shadow-xs,shadow-sm,shadow-md,shadow-lg,shadow-xl,shadow-2xl. Use a small shadow or a ring, not both at full strength. - Borders and hairlines:
border border-border, orring-1 ring-border, which does not change the size of the box. Writering-1, becauseringalone is 1 px in v4 and 3 px in v3. - Colour: use tokens such as
bg-surfaceandtext-muted-foreground. See tokens.md. The default palette also works:bg-emerald-500,text-zinc-600. The opacity modifier works on both:bg-accent/10,bg-black/5. - Gradients:
bg-linear-to-b from-accent/20 to-transparent. v4 names thembg-linear-*,bg-radialandbg-conic.
Arbitrary values
Knighn writes classes with the same rules when you edit in the properties panel. Follow them, so that the whole file has one style:
- For a spacing or a size, use a step when the size divided by 4 is a whole number:
w-280is 1120 px,h-120is 480 px, andmax-w-160is 640 px. Usepxfor 1 px. - Use an arbitrary value for a size that is not on the scale:
h-[38px],w-[134px]. - For radius, shadow, weight, line height and letter spacing, use the name only when the value is the same as the theme value. Use an arbitrary value for other values:
rounded-[10px],leading-[1.05],tracking-[-0.02em]. - For type sizes off the scale, use an arbitrary value:
text-[56px]. - For a print design, use print units:
text-[10pt],leading-[14pt],pt-[22mm],w-[210mm]. Do not change them to px by hand. CSS draws 96 px for each inch, so10ptis 13.33 px and22mmis 83.15 px. Knighn keeps the unit. - For a colour that is not a token and that appears only one time, use an arbitrary value:
bg-[#ff4f1f]. A colour that appears more than one time is a token. - For grid tracks, use an arbitrary value:
grid-cols-[240px_1fr]. Use_for a space. - For aspect ratios, use
aspect-video(16 by 9),aspect-square, or an arbitrary value such asaspect-[4/3].
Do not write p-[16px] for p-4, or w-[1120px] for w-280.
A size class such as text-sm sets the font size and the line height. When you change only the size in the properties panel, Knighn writes an arbitrary value, such as text-[14px], so that the line height stays. Both are correct.
Layout
- Stack:
flex flex-col gap-4. Row:flex items-center gap-3. - Columns:
grid grid-cols-3 gap-6. A card that spans two columns:col-span-2. - Content column:
mx-auto w-full max-w-6xl px-6. - Push items apart:
justify-between, orml-autoon the last item. - Overlays:
relativeon the parent,absolute inset-0on the overlay. - Long text in a row:
min-w-0on the text box andtruncateon the text. - Images:
size-full object-coverin a box that has a size.
Sizes map to classes like this:
| Size | In a row | In a column |
|---|---|---|
| Fixed | A step, such as w-80 (320 px), or w-[322px] off the scale |
A step, such as h-50 (200 px) |
| Hug | no width class, or w-fit |
no height class |
| Fill | flex-1, and min-w-0 when text can truncate |
self-stretch or w-full |
Container variants
Each frame with a width is a container. Container variants follow the width of the frame, not the width of the window. So one component works in a 390 px frame and in a 1440 px frame.
- Write the base classes for the narrow frame first. Add container variants for wider frames.
@3xl:px-16applies when the frame is 768 px or wider.@max-3xl:hiddenapplies when it is narrower than 768 px.- Do not use viewport variants such as
md:. See the table below.
| Viewport variant | Container variant | Starts at |
|---|---|---|
sm: |
@min-[40rem]: |
640 px |
md: |
@3xl: |
768 px |
lg: |
@5xl: |
1024 px |
xl: |
@7xl: |
1280 px |
2xl: |
@min-[96rem]: |
1536 px |
max-md: |
@max-3xl: |
below 768 px |
max-lg: |
@max-5xl: |
below 1024 px |
The container sizes, in px:
| Variant | Size | Variant | Size | Variant | Size |
|---|---|---|---|---|---|
@3xs |
256 | @lg |
512 | @4xl |
896 |
@2xs |
288 | @xl |
576 | @5xl |
1024 |
@xs |
320 | @2xl |
672 | @6xl |
1152 |
@sm |
384 | @3xl |
768 | @7xl |
1280 |
@md |
448 |
Be careful: @md: is 448 px, not 768 px. For the tablet change, use @3xl:.
What applies at the usual frame widths:
- 390 px (mobile): the base classes,
@xs:and@sm:. - 834 px (tablet): up to
@3xl:. - 1440 px (desktop): up to
@7xl:.
<section className="grid grid-cols-1 gap-6 px-6 py-16 @3xl:grid-cols-2 @3xl:px-12 @5xl:grid-cols-3 @5xl:py-24">
<div className="rounded-xl bg-surface p-6 ring-1 ring-border">One</div>
<div className="rounded-xl bg-surface p-6 ring-1 ring-border">Two</div>
<div className="rounded-xl bg-surface p-6 ring-1 ring-border">Three</div>
</section>
Nested containers
@container on an element makes it the container for its descendants. Container variants inside it follow that element, not the frame. Use it for a card that changes with its own width.
<article className="@container rounded-xl bg-surface p-6 ring-1 ring-border">
<div className="flex flex-col gap-4 @md:flex-row @md:items-center">
<div className="aspect-video rounded-lg bg-muted @md:w-48" />
<p className="text-muted-foreground">The layout of this card follows the width of the card.</p>
</div>
</article>
Give a container a name when containers are nested: @container/card and @md/card:flex-row.
Things that break in frames
All frames share one document in the editor. So classes that follow the viewport follow the editor window, and Knighn warns about them.
- Do not use
h-screen,min-h-screen,w-screenorh-dvh, orvhandvwunits. Fill the frame withsize-fullormin-h-full, and give the frame a height on the canvas. - Do not use
fixed. Useabsolutein arelativeroot, or keep the element in the flow. - Do not use
stickyfor a header. Put the header at the top of the flow. - For a width that follows the frame, use
cqw:w-[50cqw].
States
The canvas shows one state of each screen. hover:, focus: and active: classes stay in the file and show in Preview mode only. To show a state in the design:
- Hover, pressed or disabled on a component: add a variant prop, such as
state?: 'default' | 'hover' | 'disabled'withAddVariant, and put the instances side by side. - A tooltip:
await AddTooltip(id, 'Refresh data', { side: 'bottom' })puts it next to the layer. - An open menu, a hover on a screen, or a confirmation step:
AddState(screen, 'Delete confirm')copies the screen beside it as a new screen. Then change the copy: givechangessuch as{ 'Delete button': { text: 'Confirm' } }, orInsertthe menu or the dialog into itsrootas anabsolutelayer. - Keep the base screen as it is, and name each state for what it shows:
Hover,Menu open,Delete confirm.
Dark mode
Dark mode is a mode of the theme mode set. [data-theme="dark"] in the theme block changes the tokens, and the dark: variant follows the same attribute:
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
- Use tokens for colours that change:
bg-background text-foreground. They change with the mode, so you need nodark:classes. - Use
dark:only for a small change that tokens do not cover:dark:inverton a black logo. - To show a frame in dark mode, give it
modes: { theme: 'dark' }, or usePlace(…, { modes: { theme: 'dark' } }). - To show one part of a screen in dark mode, put
data-theme="dark"on its element.
<section data-theme="dark" className="flex flex-col gap-4 bg-background px-6 py-16 text-foreground">
<h2 className="text-3xl font-semibold">Built for the night shift</h2>
<p className="text-muted-foreground">This section is dark in a light screen.</p>
</section>
Class order
The order of classes is not important. Knighn sorts them in the Tailwind order when it saves. Knighn keeps classes that Tailwind does not know, and shows them as chips.