Bar Chart Examples
Publication-quality bar charts with support for vertical and horizontal orientations.
Type Interface
import type { BaseChartProps, ChartChangeEvent, Formatter, Margin } from '../../types';
/** BarChart margin: left is optional and will be auto-computed from label widths when omitted. */
export type BarChartMargin = Omit<Margin, 'left'> & { left?: number };
/**
* Columnar data for bar charts, just data no styling.
*/
export interface BarData {
/** Bar labels (x-axis for vertical, y-axis for horizontal) */
label: string[];
/** Bar values (heights for vertical, widths for horizontal) */
value: number[];
/** Optional colors for each bar (falls back to barColor or default palette) */
color?: string[];
}
export interface BarChartProps extends BarData, Omit<BaseChartProps, "legendFontSize" | "margin"> {
/** Margin around the plot area. left is optional and auto-computed from label widths when omitted. */
margin?: BarChartMargin;
/** X-axis label */
xLabel?: string;
/** Y-axis label */
yLabel?: string;
/** Chart title */
title?: string;
/** Show grid lines */
grid?: boolean;
/** Grid line color */
gridColor?: string;
/** Bar orientation */
orientation?: 'vertical' | 'horizontal';
/** Default color for all bars (overridden by colors array) */
barColor?: string;
/** Bar width as fraction of available space (0-1) */
barWidth?: number;
/** Show value labels on bars */
showLabels?: boolean;
/** Minimum Y value */
yMin?: number;
/** Maximum Y value */
yMax?: number;
/** Use canvas rendering instead of SVG */
canvas?: boolean;
/** Custom X-axis formatter */
xFormat?: Formatter;
/** Custom Y-axis formatter */
yFormat?: Formatter;
/** Callback for bar interactions */
onChange?: (event: ChartChangeEvent) => void;
/** Currently selected bar indices */
selectedIndices?: number[];
/** Callback when selection changes */
onSelectionChange?: (selectedIndices: number[]) => void;
/** Allow multiple selections (default: true) */
multiSelect?: boolean;
/** Custom overlays and children */
children?: React.ReactNode;
}
Vertical Bar Chart
A simple vertical bar chart with grid lines.
import { BarChart } from '@vuer-ai/vuer-viz';
export default function VerticalBarExample() {
return (
<BarChart
label={['A', 'B', 'C', 'D', 'E']}
value={[23, 45, 12, 67, 34]}
width={700}
height={300}
title="Sample Data"
xLabel="Categories"
yLabel="Values"
grid
/>
);
}
Horizontal Bar Chart
A horizontal bar chart with values displayed. The left margin is computed automatically from the category label lengths, so you rarely need to set it manually.
import { BarChart } from '@vuer-ai/vuer-viz';
export default function HorizontalBarExample() {
return (
<BarChart
label={['Python', 'JavaScript', 'TypeScript', 'Rust', 'Go']}
value={[85, 72, 68, 45, 56]}
width={700}
height={300}
title="Language Popularity"
xLabel="Score"
yLabel="Language"
orientation="horizontal"
grid
showLabels={true}
/>
);
}
Custom Colors with Values
Bar chart with custom colors per bar.
import { BarChart } from '@vuer-ai/vuer-viz';
export default function ColoredBarExample() {
return (
<BarChart
label={['Q1', 'Q2', 'Q3', 'Q4']}
value={[120, 145, 98, 178]}
color={['#0000ff', '#00ff00', '#ff0000', '#ffff00']}
width={700}
height={300}
title="Quarterly Revenue"
xLabel="Quarter"
yLabel="Revenue ($K)"
grid
showLabels={true}
/>
);
}
Layout & Spacing
Bar charts support flexible layout customization through margin and padding props:
padding: Uniform spacing on all sides (shorthand)margin: Fine-grained control with{ top, right, bottom, left }
// Uniform padding <BarChart padding={30} label={['A', 'B']} value={[10, 20]} /> // Custom margins per side <BarChart margin={{ top: 20, right: 40, bottom: 50, left: 60 }} label={['A', 'B']} value={[10, 20]} />
The priority order is: margin prop → padding prop → default margin with auto left.
Default margin: { top: 40, right: 20, bottom: 50, left: auto }
BarChart computes the left margin automatically from actual label widths, so you rarely need to set it manually:
- Vertical orientation: derived from the widest y-tick label
- Horizontal orientation: derived from the longest category label string
left is optional in BarChartMargin. Omit it and the chart measures the widest label to set the margin automatically. Provide an explicit left to override auto-computation.
When padding is set (and no margin prop is provided), it replaces all four sides with a single uniform value, bypassing the auto left-margin. If your chart has xLabel or yLabel, a small padding value will clip the axis labels — use margin for fine-grained control in those cases.
Default Margin
Compact(padding=50)
Custom Margin(top: 30, right: 10, bottom: 60, left: 80)
import { BarChart } from '@vuer-ai/vuer-viz';
export default function CustomPaddingExample() {
const data = {
label: ['React', 'Vue', 'Angular', 'Svelte', 'Solid'],
value: [42, 28, 21, 12, 8],
};
return (
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
<div>
<h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Default Margin</h3>
<BarChart
{...data}
width={350}
height={200}
title="Framework Usage"
yLabel="Percentage"
grid={true}
/>
</div>
<div>
<h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Compact(padding=50)</h3>
<BarChart
{...data}
width={350}
height={200}
padding={50}
title="Framework Usage"
yLabel="Percentage"
grid={true}
/>
</div>
<div>
<h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Custom Margin(top: 30, right: 10, bottom: 60, left: 80)</h3>
<BarChart
{...data}
width={350}
height={200}
margin={{ top: 30, right: 10, bottom: 60, left: 80 }}
title="Framework Usage"
yLabel="Percentage (%)"
xLabel="Framework"
grid={true}
/>
</div>
</div>
);
}
Event Handling & Selection API
BarChart supports interactive selection, allowing users to click bars to select/deselect them. This is useful for building data exploration interfaces where users can inspect details of specific bars.
Basic Selection
import { useState } from 'react'; import { BarChart } from '@vuer-ai/vuer-viz'; function MyChart() { const [selectedIndices, setSelectedIndices] = useState<number[]>([]); return ( <BarChart label={['Q1', 'Q2', 'Q3', 'Q4']} value={[120, 145, 98, 178]} selectedIndices={selectedIndices} onSelectionChange={setSelectedIndices} multiSelect={true} // Allow multiple selections (default) /> ); }
Selection Behavior
- Visual Feedback: Selected bars maintain full opacity while unselected bars fade to 30% opacity
- Click to Toggle: Click a bar to select it; click again to deselect
- Multi-select Mode: When
multiSelect={true}(default), you can select multiple bars - Single-select Mode: When
multiSelect={false}, only one bar can be selected at a time - Stroke Highlight: Selected bars show a 2px stroke outline for clear visual indication
Programmatic Control
You can programmatically control selections:
// Select specific bars setSelectedIndices([0, 2, 4]); // Clear all selections setSelectedIndices([]); // Select all bars setSelectedIndices(labels.map((_, i) => i)); // Select top N by value const selectTopN = (n: number) => { const sorted = values .map((val, i) => ({ index: i, value: val })) .sort((a, b) => b.value - a.value) .slice(0, n) .map(item => item.index); setSelectedIndices(sorted); };
Selection with Table Example
Interactive bar chart with a table showing selected items. Click bars to select/deselect them and view details in the table below.
Selected Products (0)
| Product | Sales ($K) |
|---|---|
| this table is empty | |
import { BarChart } from '@vuer-ai/vuer-viz';
import { useState } from 'react';
// Sample product sales data
const productData = {
label: ['Laptops', 'Phones', 'Tablets', 'Monitors', 'Keyboards', 'Mice', 'Headphones'],
value: [2450, 3890, 1560, 980, 650, 420, 1120],
color: ['#0000ff', '#00ff00', '#ff0000', '#ffff00', '#ff00ff', '#00ffff', '#ff8800'],
};
export default function SelectionWithTableExample() {
const [selectedIndices, setSelectedIndices] = useState<number[]>([]);
// Get selected products
const selectedProducts = selectedIndices.map(i => ({
label: productData.label[i],
value: productData.value[i],
color: productData.color[i],
}));
return (
<div className="space-y-6">
{/* Bar Chart */}
<div>
<BarChart
label={productData.label}
value={productData.value}
color={productData.color}
width={700}
height={300}
margin={{ top: 40, right: 20, bottom: 50, left: 80 }}
title="Product Sales (Click bars to select)"
xLabel="Product"
yLabel="Sales ($K)"
grid
selectedIndices={selectedIndices}
onSelectionChange={setSelectedIndices}
multiSelect={true}
/>
</div>
{/* Selected Products Table */}
<div>
<h3 className="text-lg font-semibold mb-3">
Selected Products ({selectedProducts.length})
</h3>
<div className="overflow-x-auto">
<table className="min-w-full border border-gray-300 dark:border-gray-700">
<thead className="bg-gray-100 dark:bg-gray-800">
<tr>
<th className="px-4 py-2 text-left border-b border-gray-300 dark:border-gray-700">
Product
</th>
<th className="px-4 py-2 text-left border-b border-gray-300 dark:border-gray-700">
Sales ($K)
</th>
</tr>
</thead>
<tbody>
{selectedProducts.length === 0 ? (
<tr>
<td
colSpan={2}
className="px-4 py-8 text-center text-gray-400 dark:text-gray-600 italic"
>
this table is empty
</td>
</tr>
) : (
selectedProducts.map((product, idx) => (
<tr
key={product.label}
className={idx % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800'}
>
<td className="px-4 py-2 border-b border-gray-200 dark:border-gray-700 font-mono">
<span
className="inline-block w-3 h-3 rounded-full mr-2"
style={{ backgroundColor: product.color }}
/>
{product.label}
</td>
<td className="px-4 py-2 border-b border-gray-200 dark:border-gray-700 font-semibold">
${product.value.toLocaleString()}
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
{/* Controls */}
<div className="flex gap-3 text-sm">
<button
onClick={() => setSelectedIndices([])}
className="px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
disabled={selectedProducts.length === 0}
>
Clear Selection
</button>
<button
onClick={() => setSelectedIndices(productData.label.map((_, i) => i))}
className="px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
>
Select All
</button>
<button
onClick={() => {
// Select top 3 by sales
const sorted = productData.value
.map((val, i) => ({ index: i, value: val }))
.sort((a, b) => b.value - a.value)
.slice(0, 3)
.map(item => item.index);
setSelectedIndices(sorted);
}}
className="px-3 py-1.5 bg-blue-500 hover:bg-blue-600 text-white rounded"
>
Select Top 3
</button>
</div>
</div>
);
}