NbBarChart compares numeric values across discrete categories. It supports single and multiple series; multi-series data renders as grouped bars.
<template>
<NbBarChart title="Sign-ups per channel" :series="series" />
</template>
<script setup lang="ts">
const series = [
{
name: 'Sign-ups',
data: [
{ x: 'Organic', y: 320 },
{ x: 'Referral', y: 240 },
{ x: 'Paid', y: 180 },
{ x: 'Direct', y: 150 },
],
},
]
</script>Multiple series
When more than one series shares a category, bars are grouped side-by-side.
<template>
<NbBarChart
title="Quarterly revenue by region"
subtitle="In thousands of USD"
:series="series"
/>
</template>Negative values
The Y axis automatically extends below zero when the data requires it.
Custom palette
<template>
<NbBarChart
:series="series"
:colors="[
'var(--nb-c-success)',
'var(--nb-c-warning)',
'var(--nb-c-danger)',
]"
/>
</template>Horizontal orientation
orientation="horizontal" puts the categories on the vertical axis and the values on the horizontal one. Reach for it when the category labels are words rather than short codes: vertically each label gets one band of width to fit in and they collide, horizontally each gets its own row and the full panel width.
<template>
<NbBarChart
title="Open issues by area"
orientation="horizontal"
:series="series"
/>
</template>The same data vertically, for comparison. On a wide desktop panel the labels just fit; give the chart a dashboard tile's width instead, and each category has around 60px to spend on a label that needs three times that. Horizontal is the fix, because the category axis then has the whole panel width for text:
The left gutter sizes itself to the longest label, up to 40% of the chart width. Past that the chart keeps its plot and the labels are the part that gives, so one unusually long category cannot crush the bars it belongs to.
Stacked series
stacked puts the series of a category on top of each other rather than side by side, so the bar length reads as the category total. It works in both orientations, and negative values stack downward (or leftward) from the baseline rather than cancelling the positive ones out.
<template>
<NbBarChart title="Quarterly revenue by region" stacked :series="series" />
</template>Reacting to a click
Bind @select to make the bars a way into the data behind them, typically a filtered list view.
<template>
<NbBarChart :series="series" orientation="horizontal" @select="onSelect" />
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router'
import type { IChartSeriesSelection } from '@nubisco/ui'
const router = useRouter()
const onSelect = (selection: IChartSeriesSelection) => {
// `x` is the value from your data, not the rendered label, so this keeps
// working when the axis is formatted or translated.
router.push({ name: 'issues', query: { area: String(selection.x) } })
}
</script>The payload identifies the datum rather than describing the pixel that was clicked:
| Field | Type | Description |
|---|---|---|
kind | 'series' | Discriminator shared across the chart family |
x | TChartScalar | The category value, as supplied in the data |
y | number | The value of the selected bar |
seriesName | string | Name of the series the bar belongs to |
seriesIndex | number | Index of that series |
index | number | Index of the category along the shared axis |
point | IChartPoint | The datum itself, so z and label come back |
The clickable target is the whole category band, not the exact rectangle, so a near miss still selects. In a grouped chart the position within the band picks the series; in a stacked one the position along the value axis picks the segment.
Interactivity is opt-in. With no @select listener bound, the chart is a picture: no pointer cursor, no focus ring, no button semantics. Bind one and each bar becomes a real focusable button, reachable by Tab and activated with Enter or Space, labelled with its category and value. The <svg> also stops presenting itself as a single image, so assistive technology can reach the controls inside it.
Without legend or tooltip
For dense dashboard tiles, you can suppress the chrome.