Built-in charting (one prop)
Turn on the built-in Chart panel with a single charting prop - no external library. Pick Group by / Value, choose a type, filter a column or click a bar, and the chart re-aggregates over the grid's current (filtered / sorted) rows live.
A live, editable Svelte 5 data grid example from the SvGrid gallery (Charts). See the SvGrid documentation for the full API.
What this example shows
Everything demo 147 wires by hand - aggregate the displayed rows, render a chart, keep it in sync, cross-filter - is a single `charting` prop here. Click the "Chart" toolbar button (open by default below), pick a group-by / value, and: - filter or sort the grid -> the chart re-draws live - select a cell range -> the chart scopes to those rows - click a chart bar/slice -> the grid filters to that category The chart engine is MIT core; no extra import, no glue.
Imports, features and API used
Imports: @svgrid/grid
Table features registered: rowSortingFeature, columnFilteringFeature
Columns: rep (Rep), region (Region), product (Product), quarter (Quarter), channel (Channel), revenue (Revenue), margin (Margin), deals (Deals), units (Units)
Source code (353-built-in-charting.svelte)
<!-- Documented in: docs/help/charts.md -->
<script lang="ts">
/**
* 353. Built-in charting (one prop)
* ---------------------------------
* Everything demo 147 wires by hand - aggregate the displayed rows, render a
* chart, keep it in sync, cross-filter - is a single `charting` prop here.
* Click the "Chart" toolbar button (open by default below), pick a group-by /
* value, and:
* - filter or sort the grid -> the chart re-draws live
* - select a cell range -> the chart scopes to those rows
* - click a chart bar/slice -> the grid filters to that category
* The chart engine is MIT core; no extra import, no glue.
*/
import {
SvGrid,
tableFeatures,
rowSortingFeature,
columnFilteringFeature,
type GridColumns,
} from '@svgrid/grid'
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
type Sale = {
id: number
rep: string
region: string
product: string
quarter: string
channel: string
revenue: number
deals: number
units: number
margin: number
}
const REGIONS = ['Americas', 'EMEA', 'APAC']
const PRODUCTS = ['PLC', 'Drivers', 'Rivets', 'Stock']
const QUARTERS = ['Q1', 'Q2', 'Q3', 'Q4']
const CHANNELS = ['Direct', 'Partner', 'Online']
const NAMES = ['Ada', 'Grace', 'Alan', 'Margaret', 'Linus', 'Donald', 'Brian', 'Dennis']
let seed = 0x51ce
const rnd = () => ((seed = (seed * 1103515245 + 12345) >>> 0) / 0xffffffff)
const rows: Sale[] = Array.from({ length: 96 }, (_, id) => {
const revenue = Math.round(10_000 + rnd() * 90_000)
return {
id,
rep: NAMES[id % NAMES.length]!,
region: REGIONS[id % 3]!,
product: PRODUCTS[id % 4]!,
quarter: QUARTERS[id % 4]!,
channel: CHANNELS[id % 3]!,
revenue,
deals: Math.round(2 + rnd() * 30),
units: Math.round(20 + rnd() * 480),
margin: Math.round(revenue * (0.12 + rnd() * 0.28)),
}
})
const money = { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } as const
const columns: GridColumns<Sale> = [
{ field: 'rep', header: 'Rep', width: 110 },
{ field: 'region', header: 'Region', width: 120 },
{ field: 'product', header: 'Product', width: 120 },
{ field: 'quarter', header: 'Quarter', width: 100 },
{ field: 'channel', header: 'Channel', width: 110 },
{ field: 'revenue', header: 'Revenue', width: 140, align: 'right', cellDataType: 'number', format: money },
{ field: 'margin', header: 'Margin', width: 130, align: 'right', cellDataType: 'number', format: money },
{ field: 'deals', header: 'Deals', width: 90, align: 'right', cellDataType: 'number' },
{ field: 'units', header: 'Units', width: 100, align: 'right', cellDataType: 'number' },
]
</script>
<div class="demo-page" style="height: 620px; display: flex; flex-direction: column;">
<p class="demo-hint" style="margin: 0 0 8px;">
The whole grid below is one <code><SvGrid ... charting /></code>. Try the
<strong>Group by</strong> / <strong>Value</strong> pickers, filter a column, or click a bar.
</p>
<div style="flex: 1; min-height: 0;">
<SvGrid
columnResize
data={rows}
{columns}
{features}
sortable
filterable
filterMode="row"
selectionMode="both"
containerHeight="100%"
charting={{ defaultOpen: true, width: 460 }}
/>
</div>
</div>Related documentation
Related articles
- How We Built Excel-Style Filters - How SvGrid implements per-column filter menus, type-aware operators, and a shared filter model that works identically for in-memory and server-side data.
- $bindable Props for Grid Controls in Svelte 5 - Two-way binding for grid chrome - search boxes, page-size selectors, density toggles - using $bindable to keep parent state and child input in sync without the usual wiring boilerplate.
- The Idea - Svelte 5 Deserves a Data Grid Built for It - Svelte 5 runes rewired how reactivity works. Every data grid we evaluated required a translation layer to keep up. Building one that didn't need that layer was the point.
More Charts examples
- Chart a selection (context menu) - With integrated charting enabled, the right-click menu gains a Chart selected range item: select a block of cells, right-click, and the chart panel opens scoped to that range - the Excel chart-this gesture, built in. The item appears only when charting is on and is appended to the default context menu automatically.
- Chart view of the grid - The `chart` prop turns the same <SvGrid> into a chart, driven by the grid’s filtered + sorted rows (search + sort flow through). A view of the grid like board and scheduler, but the renderer is free: the grid lazy-loads a built-in view wrapping the standalone SvChart via rowsToChartSpec. Flip Table <-> Chart (bar / line / area) over one source of truth.
- Candlestick / OHLC - Candlestick and OHLC price marks with an ordinal date axis. ChartSeries.ohlc carries the four prices while values keeps the closes, so the CSV export, the screen-reader table and a 10-day moving average all work with no candle-specific code. Toggle the axis: a real time axis opens a gap over every weekend, an ordinal one spaces sessions evenly and still labels them by date. The strip under the plot is the chart brush: drag its window to pan, drag an edge to resize.
- Box plot + error bars - Distribution rather than average: box plots with the 1.5 IQR whisker rule and individual outliers, next to the same data as a bar chart of the means with error bars. two regions with nearly identical means sit side by side in the bars and look nothing alike in the boxes. boxStats() summarises a raw sample, rowsToBoxSpec() does it per group, and ChartSeries.errors annotates any existing mark without changing its type.
- Integrated charts (no deps) - Chart the grid data with no external charting library. SvGridChart renders a ChartSpec; rowsToChartSpec aggregates the grid current (filtered/sorted) rows into one. Bar, line, area, pie - plus 100% stacked, top-N + Other, an average reference line, and double-click-to-isolate a series. Filter the grid and the chart re-aggregates live.