Sentiment Analysis Widget

Pro

5 variants: summary (semicircle gauge + breakdown + KPIs), topics (stacked sentiment bars), timeline (SVG area + volume), feed (filter pills + source badges + score bars) and aspects (sentiment per subject — what is loved and what is hated).

</>sv-sentiment-analysis-widget aisentimentanalytics
import { SvSentimentAnalysisWidgetComponent } from '@styloviz-pro/sentiment-analysis-widget';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Topics & timeline

Pro

When to use

  • Visualizing sentiment from reviews, support tickets, social or survey text.
  • You want summary gauges, per-topic breakdowns, trends and a source feed.
  • For raw numeric metrics, the Charts components are more general.

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`.
variantSentimentVariant'summary'View: summary, topics, timeline, source feed or aspects.
overallScoreSentimentScore | nullnullHeadline score and its breakdown.
topicsreadonly TopicSentiment[][]Per-topic sentiment.
feedItemsreadonly FeedItem[][]Individual pieces of feedback.
aspectMentionsreadonly SvAspectMention[][]The (aspect, opinion) pairs the `aspects` variant groups. One entry per opinion, not per document: a review saying "delivery was quick but the app crashed" is two mentions sharing an `itemId`, and keeping them separate is the whole point of the variant.
timelinereadonly TimelinePoint[] | nullnullThe series behind the timeline. Shown exactly as given — the range picker reports the user's choice through `timeRangeChange` for you to refetch. `null` renders the empty state; it does not substitute sample data.
busybooleanfalseAnalysis is in flight.
classifierSvSentimentClassifier | nullnullWhat produced these scores. A SENTIMENT NUMBER WITHOUT A CLASSIFIER IDENTITY CANNOT BE DEFENDED. "−0.42, declining" goes into a review and the first question is which model produced it and when; without an answer the figure is an opinion with a decimal point. Two figures from either side of a model swap are not comparable at all — the change measures the classifier, not the customers.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
timeRangeChangeTimeRangeEmitted when the user changes the analysis time range.
feedFilterChangeSentimentLabel | 'all'Emitted with the sentiment filter the user picks in the feed.
feedSourceChangeFeedSource | 'all'Emitted with the source filter the user picks in the feed.

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

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `topics`, `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

  • Every content set is an input defaulting to the bundled sample — `overallScore`, `topics`, `feedItems` and `timeline` — so the widget demonstrates itself out of the box and takes your analysis when you have it.
  • Leave `timeline` null and the bundled series follow the range picker; supply one and it is shown as given, with `timeRangeChange` reporting the choice for you to refetch.
  • Summary, topics, timeline and feed views.
  • Configurable sentiment thresholds.
  • Source badges and score bars.
  • Emits `timeRangeChange` when the analysis range changes.
  • `[classifier]` — model, version, languages, when it was last calibrated and its agreement with human labels — renders above every variant. A sentiment number without a classifier identity cannot be defended when somebody disputes it, and two figures from either side of a model swap are **not comparable at all**: the change measures the classifier, not the customers. With no classifier the widget says so — in every variant that has figures on screen, not only the summary — rather than rendering figures that cannot answer for themselves. Undeclared fields are named as gaps (‘Not recorded: Version, Calibrated’), and a dev build warns once when scores render without a model and its languages.
  • Calibration is not training. A model can be years old and calibrated last week, or new and never checked against this dataset — and the second is the one that quietly reports everything as mildly positive. An out-of-range `agreement` is **dropped rather than clamped**: 85 is a host that meant 0.85, and rendering '8500%' as if it were meant is worse than saying nothing.
  • `languages` is the field every dashboard omits, and its absence is a silent failure that looks like data: an English-only classifier scores German reviews as **neutral** because it cannot read them, and neutral is indistinguishable from 'no strong feelings' on every chart here. `svClassifierReads()` matches on the primary subtag, so `de` covers `de-AT`, and an undeclared list means unknown rather than none. Set `FeedItem.language` and the feed marks each item the classifier cannot read as unclassified, not neutral.

Best practices

  • Do: Render scores and breakdowns as text, not color alone, for accessibility.
  • Do: Use the timeline variant to show how sentiment shifts after a change.
  • Tip: Let users filter the feed by sentiment/source to investigate drivers.

Accessibility

  • Scores and breakdowns rendered as text.
  • Time-range and sentiment filters report aria-pressed; show-more toggles expose aria-expanded.
  • Filters are labelled, keyboard-operable controls.

Feedback on Sentiment Analysis Widget

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.