Strategic Insights
Data-driven recommendations panel combining a score gauge, key metrics strip, and prioritised action cards. Used in dashboards where the product needs to surface 'what to do next' from aggregate data.
Preview
Market Fit
Applications sent
24
+8 this week
Response rate
29%
+4% vs avg
Interview conversion
42%
↔ avg 40%
Days since last apply
2
On pace
Recommended actions
Follow up with Stripe
No response in 9 days. Send a brief note referencing your submission.
Strengthen your portfolio
3 of your top targets list case studies as a screening factor.
Apply to 2 more this week
Your response rate peaks at 8–12 applications per week.
Reach out to Linear alumni
2 people in your network previously worked there.
Structure
The panel has three layers. Each layer answers a different question for the user.
How am I doing overall?
A single number (0–100) derived from aggregate activity. The arc gauge communicates direction at a glance. Use a colour that reflects relative standing — green above threshold, amber in range, red below.
What are the key signals?
4–6 KPI tiles showing the most meaningful sub-metrics. Each tile shows value, delta, and trend direction. Limit to metrics the user can act on — vanity metrics add noise.
What should I do next?
Prioritised list of concrete, actionable suggestions derived from the metrics. Each card carries an icon, a one-line action, a brief rationale, and a priority badge (High / Medium / Low). Order by priority, limit to 4–6 items.
Scoring guidelines
The score gauge is only meaningful if the scoring logic is consistent and explainable. Follow these principles:
- →The score must be derivable from the displayed metrics. A user who reads the metric tiles should be able to understand why they received their score.
- →Define the thresholds before shipping: what score is 'good', 'average', 'at risk'? Use colours consistently with those thresholds — don't show green for a 38/100.
- →Show how the score is calculated, either as a tooltip on the gauge or a 'How is this calculated?' link. Opaque scores reduce trust.
- →Smooth transitions when the score changes — abrupt jumps feel like bugs. Use a 400–600ms ease-out animation.
- →Never show a score of 0 to a new user. Seed a reasonable baseline or show an 'insufficient data' state instead.
Implementation
interface Metric {
label: string;
value: string;
delta: string;
trend: "up" | "down" | "flat";
}
interface Recommendation {
icon: string;
title: string;
detail: string;
priority: "high" | "medium" | "low";
}
interface StrategicInsightsProps {
score: number;
scoreLabel?: string;
metrics: Metric[];
recommendations: Recommendation[];
}
const PRIORITY_COLORS = {
high: "text-red-400",
medium: "text-amber-400",
low: "text-emerald-400",
};
export function StrategicInsights({
score,
scoreLabel,
metrics,
recommendations,
}: StrategicInsightsProps) {
return (
<section aria-label="Strategic insights">
{/* Score gauge + top metrics */}
<div className="flex gap-6 items-start flex-wrap mb-6">
<div className="flex flex-col items-center gap-1">
<ArcGauge value={score} label={scoreLabel ?? `${score}`} sublabel="/ 100" />
<p className="text-[12px] font-medium text-[rgb(var(--text-secondary))]">Market Fit</p>
</div>
<div className="flex-1 grid grid-cols-2 gap-3 min-w-[200px]">
{metrics.map((m) => (
<div key={m.label}
className="rounded-lg border border-[rgb(var(--border))]
bg-[rgb(var(--surface-raised))] p-3">
<p className="text-[11px] text-[rgb(var(--text-tertiary))] mb-1">{m.label}</p>
<p className="text-[18px] font-bold text-[rgb(var(--text-primary))] leading-none mb-0.5">
{m.value}
</p>
<p className={`text-[11px] ${
m.trend === "up" ? "text-emerald-500" :
m.trend === "down" ? "text-red-400" :
"text-[rgb(var(--text-tertiary))]"
}`}>{m.delta}</p>
</div>
))}
</div>
</div>
{/* Recommended actions */}
<div className="space-y-2">
<p className="text-[11px] font-semibold uppercase tracking-wider text-[rgb(var(--text-tertiary))] mb-3">
Recommended actions
</p>
{recommendations.map((rec) => (
<div key={rec.title}
className="flex items-start gap-3 rounded-xl border border-[rgb(var(--border))]
bg-[rgb(var(--surface))] p-4 hover:bg-[rgb(var(--surface-raised))]
transition-colors">
<span className="text-xl shrink-0" aria-hidden="true">{rec.icon}</span>
<div className="flex-1 min-w-0">
<p className="text-[13px] font-semibold text-[rgb(var(--text-primary))] mb-0.5">
{rec.title}
</p>
<p className="text-[12px] text-[rgb(var(--text-secondary))] leading-relaxed">
{rec.detail}
</p>
</div>
<span className={`text-[10px] font-bold uppercase ${PRIORITY_COLORS[rec.priority]}`}>
{rec.priority}
</span>
</div>
))}
</div>
</section>
);
}Accessibility
- →The arc gauge is visual — expose the score via an accessible label on its wrapper: aria-label='Market fit score: 72 out of 100'. The SVG itself is aria-hidden.
- →Metric tiles must have distinct accessible labels. 'Response rate: 29%, up 4% vs average' is better than just '29%'.
- →Recommendation cards must be navigable by keyboard. If they carry actions (Dismiss, Act), ensure each action has a clear label including the card subject.
- →Priority badges use colour only (red/amber/green) — always include the text label ('High', 'Medium', 'Low') alongside the colour dot.
- →If the score or metrics update live, wrap the insight panel in role='region' aria-live='polite' so screen reader users are informed of changes without being interrupted.