Stats Card
Dashboard metric card for displaying KPIs with label, value, and trend description.
Quick Start
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :label) { "Total Revenue" } %>
<%= kiso(:stats_card, :value) { "$45,231.89" } %>
<%= kiso(:stats_card, :description) { "+20.1% from last month" } %>
<% end %>
Locals
| Local | Type | Default |
|---|---|---|
variant: |
:outline | :soft | :subtle |
:outline |
css_classes: |
String | "" |
**component_options |
Hash | {} |
Sub-parts
| Part | Usage | Purpose |
|---|---|---|
:header |
kiso(:stats_card, :header) |
Flex row for label + icon |
:label |
kiso(:stats_card, :label) |
Metric name (small muted text) |
:value |
kiso(:stats_card, :value) |
Big metric number (tabular-nums) |
:description |
kiso(:stats_card, :description) |
Trend text or subtitle |
All sub-parts accept css_classes: and **component_options.
Anatomy
Stats Card
├── Header (optional — only needed for label + icon)
│ ├── Label
│ └── Icon (SVG)
├── Label (if no header)
├── Value
└── Description
Use :header only when you need a label + icon row. Otherwise, place
:label directly inside the stats card.
Usage
Variant
Same visual variants as Card — matches when used alongside cards in dashboards.
<%= kiso(:stats_card, variant: :outline) do %>...<% end %>
<%= kiso(:stats_card, variant: :soft) do %>...<% end %>
<%= kiso(:stats_card, variant: :subtle) do %>...<% end %>
| Variant | Appearance |
|---|---|
outline (default) |
White background, border, subtle shadow |
soft |
Elevated background, no border |
subtle |
Elevated background with border |
With Icon
Wrap :label and an SVG inside :header to position them side by side.
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :header) do %>
<%= kiso(:stats_card, :label) { "Total Revenue" } %>
<svg class="size-4 text-muted-foreground">...</svg>
<% end %>
<%= kiso(:stats_card, :value) { "$45,231.89" } %>
<%= kiso(:stats_card, :description) { "+20.1% from last month" } %>
<% end %>
Stats Grid
Use kiso(:stats_grid) to arrange stats cards in a responsive grid.
<%= kiso(:stats_grid, columns: 4) do %>
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :label) { "Revenue" } %>
<%= kiso(:stats_card, :value) { "$45,231" } %>
<%= kiso(:stats_card, :description) { "+20.1%" } %>
<% end %>
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :label) { "Subscribers" } %>
<%= kiso(:stats_card, :value) { "+2,350" } %>
<%= kiso(:stats_card, :description) { "+180.1%" } %>
<% end %>
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :label) { "Active Now" } %>
<%= kiso(:stats_card, :value) { "+573" } %>
<%= kiso(:stats_card, :description) { "+201 this hour" } %>
<% end %>
<%= kiso(:stats_card) do %>
<%= kiso(:stats_card, :label) { "Growth" } %>
<%= kiso(:stats_card, :value) { "4.5%" } %>
<%= kiso(:stats_card, :description) { "+0.5%" } %>
<% end %>
<% end %>
| Columns | Breakpoints |
|---|---|
2 |
1 col → 2 col at sm |
3 |
1 col → 3 col at sm |
4 (default) |
1 col → 2 col at sm → 4 col at lg |
Stats Grid locals: columns: (2, 3, 4), css_classes:, **component_options
Theme
Kiso::Themes::StatsCard = ClassVariants.build(
base: "flex flex-col gap-2 rounded-xl p-4 text-foreground",
variants: {
variant: {
outline: "bg-background ring ring-inset ring-border shadow-sm",
soft: "bg-elevated/50",
subtle: "bg-elevated/50 ring ring-inset ring-border"
}
},
defaults: { variant: :outline }
)
StatsCardHeader = ClassVariants.build(base: "flex items-center justify-between gap-2")
StatsCardLabel = ClassVariants.build(base: "text-sm font-medium text-muted-foreground")
StatsCardValue = ClassVariants.build(base: "text-2xl font-semibold tabular-nums")
StatsCardDescription = ClassVariants.build(base: "text-xs text-muted-foreground")
StatsGrid = ClassVariants.build(
base: "grid grid-cols-1 gap-4",
variants: { columns: { 2 => "sm:grid-cols-2", 3 => "sm:grid-cols-3", 4 => "sm:grid-cols-2 lg:grid-cols-4" } },
defaults: { columns: 4 }
)
Accessibility
Stats Card renders as a <div> with data-component="stats_card". Sub-parts
use data-stats-card-part attributes for identity.