AI Insight Cards

Free

5 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.

</>sv-ai-insight-cards aiinsightscards
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 demo

More examples

Panel & feed

example.htmlAngular
<sv-ai-insight-cards variant="panel" [insights]="insights()" />
<sv-ai-insight-cards variant="feed" [insights]="insights()" />

An anomaly scale that fits the domain

example.htmlAngular
<!-- 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

NameTypeDefaultDescription
loadingbooleanfalseTrue while the data is being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
variantInsightVariant'feed'Presentation: `'feed'`, `'grid'`, `'inline'`, `'panel'` or `'anomaly'`.
insightsreadonly AiInsight[][]The insights to show. Decisions are layered locally, never written back.
baselinesreadonly 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.
busybooleanfalseA fetch is in flight.
simulatebooleanfalseReload 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.
anomalyMinSamplesnumberSV_ANOMALY_MIN_SAMPLESObservations 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.
anomalyNotablenumberSV_ANOMALY_NOTABLESigma 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.
anomalySeverenumberSV_ANOMALY_SEVERESigma at which it is worth waking somebody.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
insightAcceptstringEmitted with the id of an insight the user accepts.
insightDismissstringEmitted with the id of an insight the user dismisses.
refreshRequestedvoidEmitted 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.

usage.htmlAngular
<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.

host.component.tsTypeScript
// 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.

Loads giscus.app and GitHub — nothing is fetched until you click.