Guide: Dashboards, tables and charts
## Tables
Tables
- Use
table,thead,tbody,tr,thandtd. Give the cells of one column the same padding, alignment and text style. - Give a fixed column its width on the
th:w-30is 120 px. The other columns share the rest. - Make rows 40 to 48 px high, with 12 to 16 px of padding in the cells. Use a fill on alternate rows only in a dense table.
- Align numbers to the right, with
tabular-nums. Write dates in one format, such as3 Oct 2026. - Write each row out. For many rows, build the TSX in the
executesnippet with.map(). - Show status with a
Badgecomponent that has a variant for each status.
See the recipe in layout.md.
Dashboards
- Put a row of metric cards at the top: instances of one
Metriccomponent ingrid grid-cols-4 gap-4. - Put charts and tables under it in a grid of two columns:
grid grid-cols-[2fr_1fr] gap-4. - Give each card a title, and put the time range at the top right.
See the recipe in layout.md.
Charts
Make a bar chart from flex items. Give the chart a fixed height, and give each bar a height in percent. Put the labels in a second row with the same columns:
<div data-name="Bar chart" className="flex flex-col gap-2">
<div className="flex h-48 items-end gap-2">
<div className="h-[40%] flex-1 rounded-t bg-accent/30" />
<div className="h-[65%] flex-1 rounded-t bg-accent/30" />
<div className="h-[50%] flex-1 rounded-t bg-accent/30" />
<div className="h-[85%] flex-1 rounded-t bg-accent" />
<div className="h-[70%] flex-1 rounded-t bg-accent/30" />
</div>
<div className="flex gap-2 text-center text-xs text-muted-foreground">
<span className="flex-1">Mon</span>
<span className="flex-1">Tue</span>
<span className="flex-1">Wed</span>
<span className="flex-1">Thu</span>
<span className="flex-1">Fri</span>
</div>
</div>
Make a line chart with an svg and a polyline. preserveAspectRatio="none" stretches it to its box, and vectorEffect="non-scaling-stroke" keeps the line width:
<svg
viewBox="0 0 300 100"
preserveAspectRatio="none"
aria-hidden="true"
className="h-40 w-full text-accent"
>
<polyline
points="0,80 50,62 100,70 150,44 200,50 250,24 300,16"
fill="none"
stroke="currentColor"
strokeWidth={2}
vectorEffect="non-scaling-stroke"
/>
</svg>
Make a donut with two circles. A radius of 15.9155 gives a circumference of 100, so strokeDasharray="70 30" shows 70 percent:
<svg viewBox="0 0 36 36" aria-hidden="true" className="size-32 text-accent">
<circle
cx="18"
cy="18"
r="15.9155"
fill="none"
stroke="currentColor"
strokeOpacity={0.15}
strokeWidth={4}
/>
<circle
cx="18"
cy="18"
r="15.9155"
fill="none"
stroke="currentColor"
strokeWidth={4}
strokeDasharray="70 30"
transform="rotate(-90 18 18)"
/>
</svg>
- Do not put labels on a chart by hand with absolute positions. Let flex align them with the bars.
- Use the accent colour for the data that is important, and a light tint of it for the rest.