ngx-charts
ngx-charts is a charting library built specifically for Angular on top of D3. Instead of imperatively wiring up SVG and scales yourself, you describe charts declaratively in your templates with components like <ngx-charts-bar-vertical> or <ngx-charts-line-chart>, binding plain data and options. It handles the heavy lifting — D3 scales, axes, legends, tooltips, animations, and responsive resizing — while giving you Angular-native inputs, outputs, and ng-template customization. This makes it a natural fit when you want common chart types that look good out of the box and integrate cleanly with Angular’s change detection and signals.
Installing ngx-charts
ngx-charts depends on D3, which is installed alongside it. The ng add schematic registers the package and the required browser animations provider in one step.
ng add @swimlane/ngx-charts
If you prefer to install manually, add the package and ensure animations are provided in your application config.
Output:
✔ Package information loaded.
The package @swimlane/[email protected] will be installed and executed.
UPDATE package.json
UPDATE src/app/app.config.ts (added provideAnimations)
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [provideAnimations()],
};
ngx-charts relies on Angular’s animations module for its enter/update transitions. If
provideAnimations()is missing, charts still render but without animated transitions and you may see runtime errors on some chart types.
Rendering your first chart
ngx-charts exposes standalone components, so you import only the chart you use. Data is supplied as an array of { name, value } objects (or series objects for multi-series charts). The example below uses signals for the data and a colorScheme object that ngx-charts maps onto its D3 color scales.
import { Component, signal } from '@angular/core';
import { BarChartModule } from '@swimlane/ngx-charts';
@Component({
selector: 'app-traffic-chart',
standalone: true,
imports: [BarChartModule],
template: `
<ngx-charts-bar-vertical
[results]="data()"
[scheme]="scheme"
[xAxis]="true"
[yAxis]="true"
[showXAxisLabel]="true"
[showYAxisLabel]="true"
xAxisLabel="Day"
yAxisLabel="Visitors"
[animations]="true"
(select)="onSelect($event)"
/>
`,
styles: `:host { display: block; height: 400px; }`,
})
export class TrafficChartComponent {
readonly scheme = { domain: ['#3b82f6', '#6366f1', '#8b5cf6'] };
readonly data = signal([
{ name: 'Mon', value: 4200 },
{ name: 'Tue', value: 5100 },
{ name: 'Wed', value: 3900 },
{ name: 'Thu', value: 6400 },
{ name: 'Fri', value: 7300 },
]);
onSelect(event: { name: string; value: number }): void {
console.log('Clicked bar:', event.name, event.value);
}
}
Output:
Clicked bar: Thu 6400
The chart sizes itself to its container, so giving the host element an explicit height (as above) is essential — without a sized parent, the SVG collapses to zero height.
Common chart types
Each chart type is its own component with a focused set of inputs. Multi-series charts (line, area, grouped/stacked bar) expect a nested series array rather than flat values.
| Chart | Component | Data shape |
|---|---|---|
| Vertical bar | ngx-charts-bar-vertical | { name, value }[] |
| Grouped bar | ngx-charts-bar-vertical-2d | { name, series: { name, value }[] }[] |
| Line | ngx-charts-line-chart | { name, series: { name, value }[] }[] |
| Area | ngx-charts-area-chart | { name, series: { name, value }[] }[] |
| Pie / donut | ngx-charts-pie-chart | { name, value }[] |
| Heat map | ngx-charts-heat-map | { name, series: { name, value }[] }[] |
A multi-series line chart consumes the nested shape directly:
import { Component, signal } from '@angular/core';
import { LineChartModule } from '@swimlane/ngx-charts';
@Component({
selector: 'app-revenue-chart',
standalone: true,
imports: [LineChartModule],
template: `
<ngx-charts-line-chart
[results]="series()"
[legend]="true"
[xAxis]="true"
[yAxis]="true"
[autoScale]="true"
/>
`,
styles: `:host { display: block; height: 400px; }`,
})
export class RevenueChartComponent {
readonly series = signal([
{
name: '2025',
series: [
{ name: 'Q1', value: 120 },
{ name: 'Q2', value: 180 },
{ name: 'Q3', value: 150 },
{ name: 'Q4', value: 210 },
],
},
{
name: '2026',
series: [
{ name: 'Q1', value: 160 },
{ name: 'Q2', value: 200 },
{ name: 'Q3', value: 240 },
{ name: 'Q4', value: 300 },
],
},
]);
}
Customizing tooltips and labels
Most charts accept projected ng-template content for tooltips and labels, letting you render arbitrary Angular markup with the chart’s context. Use the appropriate template reference — tooltipTemplate for the hover tooltip on bar charts, for example.
<ngx-charts-bar-vertical [results]="data()" [scheme]="scheme">
<ng-template #tooltipTemplate let-model="model">
<div class="tip">
<strong>{{ model.name }}</strong>
<span>{{ model.value | number }} visitors</span>
</div>
</ng-template>
</ngx-charts-bar-vertical>
You can also format axis ticks with a function bound to [xAxisTickFormatting] or [yAxisTickFormatting], which keeps formatting logic in your component:
formatThousands = (value: number): string => `${value / 1000}k`;
Pass
[animations]="false"for charts that re-render frequently (such as live dashboards). Replaying D3 enter animations on every data tick is expensive and causes visible flicker.
Best Practices
- Always give the chart’s host or wrapper element an explicit height; ngx-charts measures its container and renders nothing useful inside a zero-height box.
- Replace the whole signal/array reference when updating data so Angular’s change detection and ngx-charts’ diffing pick up the change — mutating the existing array in place may not trigger a redraw.
- Import only the specific chart module (
BarChartModule,LineChartModule, etc.) rather thanNgxChartsModuleto keep bundles small and tree-shakeable. - Define color schemes as a stable
{ domain: string[] }object reference (a class field) instead of an inline object literal in the template to avoid needless re-renders. - Disable animations on high-frequency real-time charts, and prefer
[autoScale]="true"for clearer axes on data that does not start at zero. - Use
ng-templatecustomization for tooltips and labels instead of forking the library when the defaults do not match your design system.