KPI Card
Dashboard metric card with icon, title, value (numericText animation), tint color, and customizable trailing slot. Includes SWKPIDeltaTag for period-over-period comparison
Copies a short instruction with your private download link. Paste it into your agent: it downloads the whole skill (the source code, the setup steps and the mistakes we already made for you) and builds the screen.
Works with
What it does
SWKPICard is a dashboard KPI tile designed for revenue dashboards, analytics summaries, and admin panels where multiple metrics are arranged in a 2×N grid. It has three layout layers:
- Header row -- SF Symbol icon (tinted) + title in
caption.secondary. - Hero value --
title2.boldin the tint color, animated via.contentTransition(.numericText())so updating the value smoothly morphs the digits. - Trailing slot -- a
@ViewBuilderclosure for delta tags, unit labels, date ranges, or any caption-level metadata. The caller has full control over what sits in this slot.
Card chrome: 14pt padding, 16pt corner radius systemBackground fill (with macOS windowBackgroundColor equivalent), a faint black 0.04 shadow, and a tint × 0.15 stroke. Designed to sit on a soft-colored page background (cream, ivory, gray.opacity(0.06)) rather than pure white.
Ships with a companion SWKPIDeltaTag view -- a stock period-over-period indicator (green up-arrow / red down-arrow + signed percentage + comparison label). It gracefully degrades to a "No data" placeholder when delta is nil, so card chrome stays consistent across populated and empty states.
On value formatting: the caller is responsible for formatting the value string. This keeps the component locale-agnostic and lets you control currency symbols, thousand separators, and unit suffixes ("$1.2K", "¥1,234", "42 cups", "98%", etc.).
A convenience initializer (extension where Trailing == EmptyView) lets you omit the trailing closure entirely when no metadata is needed.
What you get
- ✓368 lines of source code, ready to paste
- ✓Source Code
- ✓Usage
Usage
// 1. Single card with SWKPIDeltaTag trailing (most common dashboard pattern)
SWKPICard(
title: "Today's Revenue",
value: "$1,234",
icon: "dollarsign.circle.fill",
tint: .brown
) {
SWKPIDeltaTag(delta: 12.5)
}
// 2. No trailing slot (convenience initializer where Trailing == EmptyView)
SWKPICard(
title: "Total Members",
value: "1,024",
icon: "person.3.fill",
tint: .blue
)
// 3. Custom trailing -- unit label, date range, or any caption-level metadata
SWKPICard(
title: "Cups Sold",
value: "128",
icon: "cup.and.saucer.fill",
tint: .orange
) {
Text("Unit: cups")
.font(.caption2)
.foregroundStyle(.secondary)
}
// 4. 2-column grid layout (typical dashboard)
LazyVGrid(
columns: [
GridItem(.flexible(), spacing: 12),
GridItem(.flexible(), spacing: 12)
],
spacing: 12
) {
SWKPICard(title: "Revenue", value: "$1,234", icon: "dollarsign.circle.fill", tint: .brown) {
SWKPIDeltaTag(delta: 12.5)
}
SWKPICard(title: "Orders", value: "42", icon: "bag.fill", tint: .blue) {
SWKPIDeltaTag(delta: -3.2)
}
SWKPICard(title: "New Members", value: "8", icon: "person.2.fill", tint: .pink) {
SWKPIDeltaTag(delta: nil) // graceful "No data" fallback
}
SWKPICard(title: "Conversion", value: "4.2%", icon: "chart.line.uptrend.xyaxis", tint: .green) {
SWKPIDeltaTag(delta: 0.8, comparisonLabel: "vs last week")
}
}
// 5. Animated value updates (the .numericText() content transition is built-in)
struct DashboardView: View {
@State private var revenue: Int = 1234
private let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()
var body: some View {
SWKPICard(
title: "Revenue",
value: "$\(revenue)",
icon: "dollarsign.circle.fill",
tint: .brown
) {
SWKPIDeltaTag(delta: 12.5)
}
.onReceive(timer) { _ in
withAnimation { revenue += Int.random(in: 1...100) }
// digits smoothly morph via .contentTransition(.numericText())
}
}
}More in Components
- Add SheetFreeBottom sheet with text input field, Cancel and Continue buttons, presented as a medium detent sheet
- Alert Toast NotificationFreeGlobal toast-style alert overlay with preset styles (info, success, warning, error) and auto-dismiss
- Bullet Point TextFreeText label with a colored capsule bullet point indicator that accepts any View content via @ViewBuilder
- Cached ImageFreeAsyncImage drop-in with a memory + disk cache, so re-created views show remote images on the first frame instead of flashing the placeholder
- Floating LabelsFreeAnimated floating capsule labels that fade in and out at specified positions around an image
- Gradient DividerFreeHorizontal divider with a center-fade gradient effect (clear to color to clear)