AI Insight Cards
Free5 variants: `feed` (priority-ordered list), `grid` (confidence-ring cards), `inline` (single featured insight), `panel` (detailed insight with evidence) and `anomaly` (the baseline behind each claim) — with confidence provenance, evidence links, trend arrows, sparklines and action buttons.
import { SvAiInsightCardsComponent } from '@styloviz/ai-insight-cards';Demo & usage
Basic usage
Usage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Panel & feed
<sv-ai-insight-cards variant="panel" [insights]="insights()" /> <sv-ai-insight-cards variant="feed" [insights]="insights()" />
An anomaly scale that fits the domain
<!-- The defaults are 14 observations, 3 sigma and 5 sigma. They are reasonable for a DAILY business metric and wrong nearly everywhere else: a fortnight of hourly data is 336 observations, a fortnight of monthly data is not a baseline at all. The floor the component applies is also the number the card SHOWS when it refuses to judge, so moving it moves the explanation with it. --> <sv-ai-insight-cards variant="anomaly" [baselines]="hourlyMetrics()" [anomalyMinSamples]="336" [anomalyNotable]="2.5" [anomalySevere]="4" />
When to use
- Surfacing AI-generated insights with confidence, trend and supporting actions.
- Analytics summaries, anomaly callouts, recommendation feeds.
- For raw metrics without AI framing, use Stat Cards or a Widget Grid.
Async states
- loading
- error
- retry
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the data is being fetched. |
| error | SvDataError | string | null | null | Load failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`. |
| variant | InsightVariant | 'feed' | Presentation: `'feed'`, `'grid'`, `'inline'`, `'panel'` or `'anomaly'`. |
| insights | readonly AiInsight[] | [] | The insights to show. Decisions are layered locally, never written back. |
| baselines | readonly SvInsightBaseline[] | [] | The series behind each claim, for the `anomaly` variant. One entry per metric: its recent history and its current reading. The deviation is computed here rather than taken from the host because the arithmetic is where the mistakes are. |
| busy | boolean | false | A fetch is in flight. |
| simulate | boolean | false | Reload with the bundled sample when Refresh is pressed. **Off by default.** Refresh emits `refreshRequested` and waits for a new `insights` — production behaviour must not depend on an integrator remembering to turn a demo switch off. Set it explicitly to `true` in a showcase, where a fabricated reload is the point. |
| anomalyMinSamples | number | SV_ANOMALY_MIN_SAMPLES | Observations required before any severity is claimed. THE DEFAULT IS A POLICY ABOUT SOMEBODY ELSE'S DOMAIN. Fourteen is right for a daily business metric and wrong almost everywhere else: a fortnight of hourly data is 336 observations, a fortnight of monthly data is not a baseline at all, and a seasonal series needs a season. The figure was well reasoned and still a guess, so it is a default and not a rule — and it is the number the card SHOWS when it refuses to judge, so moving it moves the explanation with it. |
| anomalyNotable | number | SV_ANOMALY_NOTABLE | Sigma at which a finding is worth a look. Also the line the anomaly variant's "a mean-and-sigma detector would have missed this" note judges by and quotes. |
| anomalySevere | number | SV_ANOMALY_SEVERE | Sigma at which it is worth waking somebody. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| retry | void | The host should re-run the failed load. |
| insightAccept | string | Emitted with the id of an insight the user accepts. |
| insightDismiss | string | Emitted with the id of an insight the user dismisses. |
| refreshRequested | void | Emitted when the user asks for fresh insights. |
Wire it to your API
This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.
Template
Bound to the names this component actually exposes.
<sv-ai-insight-cards [insights]="data.items()" [loading]="data.loading()" [error]="data.error()" (retry)="data.reload()" />
Host class
Drive the three async inputs from your own fetch.
// This component reports its state but does not emit a query, so drive // it from your own fetch and bind the three async inputs. readonly items = signal<Row[]>([]); readonly loading = signal(false); readonly error = signal<SvDataError | null>(null); async load(): Promise<void> { this.loading.set(true); this.error.set(null); try { this.items.set(await this.api.fetchRows()); } catch (e) { this.error.set(toSvDataError(e)); } finally { this.loading.set(false); } }
- This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `insights`, `loading` and `error`.
- Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.
Full walkthrough: Connecting to a backend.
Customization & theming
- `insights` defaults to an empty list, so the board renders nothing it was not given; the exported `DEMO_INSIGHTS` are for showcases, and each carries `sample: true` so the card says so on screen. Accept and dismiss are layered locally and reported as outputs — the array you pass is never mutated.
- `simulate` is off by default, so Refresh only emits `refreshRequested` and `busy` drives the loading state. Set it to true only in a showcase, where a fabricated reload is the point.
- Grid, detail, comparison and digest layouts.
- Confidence scores and trend indicators.
- Inline sparklines and actions.
- Emits `insightAccept` / `insightDismiss` with the insight id.
- The anomaly scale is host policy, not arithmetic: `[anomalyMinSamples]`, `[anomalyNotable]` and `[anomalySevere]` default to the exported `SV_ANOMALY_MIN_SAMPLES` (14), `SV_ANOMALY_NOTABLE` (3σ) and `SV_ANOMALY_SEVERE` (5σ), which are still exported for callers using `svAnomaly` directly. A figure that is not a positive finite number falls back to the default rather than being clamped near it, and `svResolveAnomalyThresholds` is exported so a host can see what the component settled on.
- `evidenceUrl` is where a reader goes to check a claim, and an insight without one **renders as an assertion** rather than as a finding. The item asked for a *required* field; optional-and-visible is the stronger of the two — a required field is satisfied by `''`, turns every existing host into a compile error, and buys nothing the reader can see, whereas 'No evidence linked — this is an assertion' cannot be satisfied by typing quotes. A non-http(s) scheme is refused rather than rendered as a dead `unsafe:` link, which would teach the reader that evidence links do not work rather than that this one is wrong. The evidence link, the assertion label and the confidence basis render in **every** variant that shows a confidence — `feed`, `grid`, `inline` and `panel` — sized for each, not in the feed alone.
- `confidenceBasis`, `model` and `modelVersion` travel with the percentage, and the figure still renders when they are missing — saying 'no method or model recorded' rather than hiding a number the host already shows. '87%' reads as calibrated when it is usually a model rating its own certainty.
- `sample: true` marks the kit’s own demo insights, and every entry in `DEMO_INSIGHTS` carries it. The card says so on screen. A board rendering believable insights with no data wired is indistinguishable from one rendering real ones, and that array is one copy-paste from a host’s fixture and one deploy from a board somebody trusts — so the label travels with the **data**, not with the component’s mode, because that is the path it actually takes.
Best practices
- Do: Always show a confidence score so users can calibrate trust in each insight.
- Do: Pair every insight with a concrete next action.
- Don't: Don't present low-confidence insights with the same weight as high-confidence ones.
- Do: Set `[anomalyMinSamples]` to what a baseline means in your domain. The default of 14 observations suits a daily metric; hourly data reaches 14 before breakfast, and monthly data will not reach it this year. Under the floor the component withholds severity entirely rather than downgrading it — a finding off too little history is not a milder finding, it is not a finding.
- Don't: Don't set `[anomalySevere]` below `[anomalyNotable]`. Every finding past the notable line would also be past the severe one, so the middle band would vanish while the legend still offered three; the component clamps the two together and says so in a dev warning.
Accessibility
- Confidence and trends conveyed as text.
- Priority filter chips report aria-pressed.
- Action buttons are labelled.
- A finding with too little history behind it says so in words, and says the floor it was judged against — the number travels with the finding, so the sentence cannot state a threshold that had nothing to do with the verdict.
Feedback on AI Insight Cards
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.