Angular Progress, Meter & Ring | ng-hub-ui-metrics
Read-only Angular metric primitives — a linear progress bar, a graded meter and a circular ring gauge — driven by design-system tokens with full ARIA semantics.
Last updated Sep 28, 2026
Overview
Why teams search for this library
Use ng-hub-ui-metrics when your Angular application needs to visualize a single value — upload progress, capacity, a score or a rating — without pulling in a full charting library.
Install
npm install ng-hub-ui-metricsJump to
Ideal for
- upload and task progress
- disk, memory and capacity meters
- quality scores and ratings
- dashboard KPI rings
About metrics
ng-hub-ui-metrics is a small family of presentational primitives. `hub-progress` renders a determinate or indeterminate linear bar; `hub-meter` grades a scalar against a `[low, high]` plateau following HTML `<meter>` semantics; `hub-ring` draws a normalized score as an SVG arc with an optional projected caption. None of the components hard-code a colour — they read the shared `--hub-sys-color-*` families and expose `--hub-progress-*`, `--hub-meter-*` and `--hub-ring-*` custom properties for theming.
Feature guides
Linear progress
A determinate or indeterminate progress bar with a size scale, semantic colours and an optional value label.
Examples:
Progress bars
Progress bars
Graded meter
A gauge following HTML <meter> semantics that recolours itself by band relative to the low/high plateau and the optimum point.
Examples:
Graded meters
Graded meters
The caption beside each bar is plain text: it is not attached to the gauge, and a meter is named by its author alone. label is what a screen reader reads out — it renders nothing, so the demo looks the same with it and without it.
Circular ring gauge
An SVG ring rendering a normalized score, with colour thresholds and a caption projected through <ng-content>.
Examples:
Ring gauges
Ring gauges
The projected caption is decoration, and so is the percentage in the middle: neither names a role="meter". label does, and it is the only way in — a ring used to announce itself as "92%", which says nothing about what was measured.
Theming
Tint one primitive with the semantic `color` input (mapped to the ds `--hub-sys-color-*` families), or retint all three at once with the one-call `hub-metrics-theme()` SCSS mixin and the `--hub-*` custom properties.
Examples:
Theming with the mixin & semantic colours
Theming with the mixin & semantic colours
color input reads the design-system --hub-sys-color-* familieshub-metrics-theme() include retints all three primitives at once (see the CSS tab)Key features
Recent changes
Version 22.5.1 - 9/28/26, 12:00 AM
changed: The family list in both READMEs names `ng-hub-ui-spreadsheet`. The sheet joined the family and the other lists had not caught up. Documentation only: no code, types or styles change.
Version 22.5.0 - 9/23/26, 12:00 AM
changed: BREAKING: the Angular floor rises from 17.1.0 to 17.3.0. The old range was measured from the source alone, and its published `.d.ts` names `InputSignalWithTransform` or `OutputEmitterRef`, which Angular did not ship until 17.3. An application below the new floor could install this package and then fail to build; it now gets the peer warning it should always have had. Nothing that worked stops working. See BREAKING_CHANGES.md.
Version 22.4.3 - 9/23/26, 12:00 AM
changed: The Angular peer range now says what the code needs. It asked for >=21.0.0, which nothing in this package justified: the newest Angular API the source uses is input(), which shipped in 17.1, and the compiled output carries no linker marker above it. The range is >=17.1.0, and npm run peers:floors derives and checks that floor from now on.
Version 22.4.2 - 9/21/26, 12:00 AM
fixed: hub-ring announces the value it actually draws. aria-valuenow was bound to the raw value while the arc paints the ratio clamped into 0..max, so a value past max drew a full ring and announced a number outside the range it was measured against.
Version 22.4.1 - 9/16/26, 12:00 AM
changed: Repository, issue and README links follow the move to the hub-env organization. Issues for every Hub UI package are now gathered in hub-env/hub-ui, and the repository and bugs fields of the manifest point at the new addresses. No code, types or styles change.
Version 22.4.0 - 9/8/26, 12:00 AM
changed: The three primitives keep their stylesheet to themselves. <hub-progress>, <hub-meter> and <hub-ring> shipped with ViewEncapsulation.None, which publishes every rule they emit into the application's global cascade, where it competes with rules the library never sees and cannot be removed by anyone who did not know it was there. None of the four reasons CODING_RULES.md allows for leaving encapsulation applied here: all three paint their own host and their own template and nothing else. The token defaults move from :where(.hub-progress) to :where(:host), which costs nothing because a custom property inherits, and the size and band modifiers, which ride on the host, are matched through :host(). Theming is untouched: the defaults stay at specificity zero and hub-metrics-theme() still emits its rules from your own sheet against the host element. See BREAKING_CHANGES.md for the one case that does change.
added: ng-hub-ui-ds is declared as an optional peer dependency (>=22.0.0). Every token in the three stylesheets has always resolved through the --hub-sys-* / --hub-ref-* ladder and the manifest said nothing about it, so a consumer reading the package on npm had no way to learn that installing the token package is what gives these primitives the family palette and its dark mode. It stays optional because it truly is: each token carries a literal fallback and the library renders without it.
Version 22.3.0 - 9/6/26, 12:00 AM
added: <hub-meter> and <hub-ring> accept a label input, mirroring <hub-progress>. An element with role=meter is named by its author alone: the meter renders no text of its own and the caption projected into the ring is not a name, so both primitives reached assistive technology unnamed and the ring could not even be named from outside. The input feeds aria-label through a host binding and is dropped when empty, so an outer aria-labelledby still applies; an aria-label written on the element itself does not, because the host binding owns the attribute and clears it whenever label is unset. See BREAKING_CHANGES.md.
added: FUNCTIONALITIES.md, the coverage table the rest of the family ships. Nothing stated which parts of the three primitives a live example actually demonstrates and which are only described in prose, so a reader had to open the docs site and infer it.
fixed: <hub-ring> no longer takes its accessible name from its own percentage. aria-label was hard-wired to the rounded value already carried by aria-valuetext, which announced the number twice and overwrote any name written on the element. The name now comes from the new label input, and the percentage stays in aria-valuetext.
fixed: <hub-ring> size and thickness no longer shadow their own tokens. Both defaulted to a concrete length written inline as a custom property on every render, so --hub-ring-size and --hub-ring-thickness, advertised as themeable by the README, the CSS reference and the ds token spec, could only be overridden with !important, and not even the hub-metrics-theme() mixin reached them. The inputs now default to undefined (their type widens accordingly) and the inline declaration is dropped when unset, leaving the stylesheet in charge with 4rem and var(--hub-ref-space-2, 0.5rem), the same values as before. Same shape as the 22.0.1 fix for the color input of <hub-progress>.
fixed: The README no longer advertises zero external dependencies. ng-hub-ui-utils has been a required peer since 22.2.0, because <hub-progress> imports resolveHubAccent from it, so anyone who followed the Quick Start installed a tree that cannot resolve. Both READMEs now state the dependency and the install command names it.
fixed: The <hub-progress> token table lists --hub-progress-accent. It is the root slot written by the color input and by the $accent of the mixin, and the one every other progress token derives from, yet it was the single token the table left out, so a theme author reading only the README could not see what to override.
fixed: HubRingThresholds.low described itself as inclusive (at or below) while the component treats a value equal to low as neutral. The JSDoc ships in the .d.ts, so the wrong sentence is what a consumer reads in their editor.
Version 22.2.4 - 9/1/26, 12:00 AM
changed: The homepage in the manifest points at this library's own documentation page rather than at the site root. It is the link a registry shows beside the package and the one a reader clicks from it, and landing on a front page they then have to search is a worse answer than landing on the reference for the package they were already looking at. Metadata only — no code, no types, no styles change, and nothing a consumer imports is affected.
Version 22.2.3 - 8/17/26, 12:00 AM
fixed: The published package declared no licence. An absent license field is not neutral — a registry reports it as unlicensed, which legally reads as all rights reserved, the most restrictive state possible rather than the most open. The intent was always MIT; it is now stated in package.json and carried in a LICENSE file that ships with the package.
Version 22.2.2 - 8/8/26, 12:00 AM
fixed: Documentation links now point at the canonical localized URLs. The README linked to https://hubui.dev/<path> with no locale prefix and no trailing slash, and both forms are 301-redirected, so every reader arriving from npm or GitHub landed on a redirect instead of the canonical page.
Version 22.2.1 - 7/28/26, 12:00 AM
fixed: The package could not be published: tsconfig.lib.prod.json was missing "compilationMode": "partial", so production builds emitted full Ivy output, which npm publishing rejects. 22.2.0 never reached the registry; this release carries the 22.2.0 changes (canonical resolveHubAccent from ng-hub-ui-utils) plus the build fix.
Version 22.2.0 - 7/28/26, 12:00 AM
changed: Accent resolution now imports the canonical resolveHubAccent from ng-hub-ui-utils. The private copy under src/lib/shared/resolve-hub-accent.ts (used by <hub-progress>) has been deleted in favour of the single, tested implementation shared family-wide. Behaviour is identical (the copy had not diverged): a bareword resolves to var(--hub-sys-color-<name>, <name>), a literal colour passes through unchanged, an empty value yields null.
added: NEW peer dependency: ng-hub-ui-utils >=22.7.0. Consumers must have ng-hub-ui-utils installed alongside this library (it is where resolveHubAccent lives). Users installing via ng add ng-hub-ui get it automatically; manual installs need npm i ng-hub-ui-utils.
Version 22.1.0 - 7/7/26, 12:00 AM
changed: BREAKING (packaging) — SCSS ships at ng-hub-ui-metrics/styles. The theme mixin now builds to dist/metrics/styles/... (was dist/metrics/src/lib/styles/...), so @use 'ng-hub-ui-metrics/styles' resolves. Update any @use that reached into src/lib/styles.
changed: <hub-progress> color accepts ANY colour. On top of the built-in semantic accents, the input now also accepts a registered custom accent and a literal colour (#ff0000, rgb(...), oklch(...), a CSS named colour), resolved through the shared resolveHubAccent resolver (a local copy of the canonical ng-hub-ui-utils helper): a bareword becomes var(--hub-sys-color-<name>, <name>); a literal is used as-is. The single --hub-<comp>-accent slot derives the rest of the family, so built-in colours are unchanged.
changed: Internal — host bindings moved to the host metadata object. @HostBinding / @HostListener decorators were replaced by the host object in the component/directive metadata (Angular style guide). No public API or behaviour change.
Version 22.0.1 - 7/6/26, 12:00 AM
fixed: Wrapper / mixin theming now actually retints the primitives. Each component declares its token defaults on its own element (:where(.hub-progress) / :where(.hub-meter) / :where(.hub-ring)), and a custom property set on the element wins over one inherited from an ancestor — so a bare .wrapper { --hub-*: … } override, and the hub-metrics-theme() mixin that emitted such overrides, had no effect. The mixin now emits its token overrides ON the metrics elements as descendants of the include scope (<scope> :where(.hub-progress, .hub-meter, .hub-ring)), which beats the per-element defaults and reaches the components.
fixed: <hub-ring> host role corrected to meter (was img, which does not expose the aria-valuemin / -valuemax / -valuenow / -valuetext attributes the component sets).
changed: <hub-progress> color input is now optional (HubMetricsColor | undefined, default undefined). When set it is applied inline as a per-instance override; when omitted the accent falls back to the --hub-progress-accent token so a theme (mixin / token override) can drive it. The rendered default is unchanged (primary).
added: docs/css-variables-reference.md — complete CSS custom-property reference for <hub-progress>, <hub-meter> and <hub-ring>, with the theming guidance above.
Version 22.0.0 - 7/5/26, 12:00 AM
added: HubProgressComponent: a determinate/indeterminate linear progress bar with a size scale, semantic colours and an optional value label.
added: HubMeterComponent: a graded gauge following HTML <meter> semantics that selects its fill band from the low/high plateau and the optimum point.
added: HubRingComponent: a circular SVG ring gauge with colour thresholds, a projected centre caption and exportAs "hubGauge".
added: CSS-variable theming surface (--hub-progress-*, --hub-meter-*, --hub-ring-*) mapped onto the shared --hub-sys-color-* token families.
Related libraries
Frequently asked questions
How do I show a progress bar in Angular?
Install ng-hub-ui-metrics together with ng-hub-ui-utils, which is a required peer, and import HubProgressComponent. Then <hub-progress [value]="72" label="Upload" showValue /> renders the bar: max defaults to 100, the host carries role=progressbar with aria-valuenow, and label supplies both the visible caption and the accessible name. Set indeterminate when the duration is unknown, which drops aria-valuenow and marks the host aria-busy.
What is the difference between hub-progress, hub-meter and hub-ring?
hub-progress is a linear bar for work advancing towards completion, and it is the only one of the three with an indeterminate state and a color input. hub-meter is a reading inside a range, with low, high and optimum marking the bands, so it announces role=meter and an aria-valuetext naming the band. hub-ring draws the same idea as a circular arc with optional thresholds, and it is the only one that projects your own caption. Watch the defaults: max is 100 on progress but 1 on meter and ring, and showValue starts off on progress and on on ring.
How do I change the colour of an Angular progress bar or gauge?
hub-progress takes a color input with primary, secondary, success, danger, warning, info and neutral. hub-meter and hub-ring have no colour input at all: they are recoloured through the --hub-progress-*, --hub-meter-* and --hub-ring-* custom properties, or in one place with the hub-metrics-theme() Sass mixin. Every token falls back to a literal value, so ng-hub-ui-ds is optional and the components render with or without it.
Does ng-hub-ui-metrics collect analytics or draw charts?
No, on both counts. It ships three read-only elements that paint the numbers you hand them, and it measures nothing, stores nothing and sends nothing anywhere. There is no chart, no sparkline, no KPI card and no animated counter, and no charting dependency underneath: the ring is hand-written SVG. If you need a plotted series, this is not the package.