Built-in charting: date axis

Group by a real date column and the built-in Chart panel adds a Date axis toggle - proportional time gaps + real date ticks - alongside Log scale. A daily-signups sheet you can retype, re-pick, or filter 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

A daily signups sheet with a real date column. Because the group-by column is a date, the chart panel offers a **Date axis** toggle (space points by actual time, real date ticks) on top of the usual pickers - and a **Log scale** toggle for the wide-range value axis. Both are one-click, live, and persist in saved views. Filter or sort the grid and the line re-plots.

Imports, features and API used

Imports: @svgrid/grid

Columns: date (Date), channel (Channel), device (Device), signups (Signups), revenue (Revenue)

Source code (358-charting-by-date.svelte)

<script lang="ts">
  /**
   * 358. Charting by date (time axis + log scale)
   * ---------------------------------------------
   * A daily signups sheet with a real date column. Because the group-by column
   * is a date, the chart panel offers a **Date axis** toggle (space points by
   * actual time, real date ticks) on top of the usual pickers - and a **Log
   * scale** toggle for the wide-range value axis. Both are one-click, live, and
   * persist in saved views. Filter or sort the grid and the line re-plots.
   */
  import { SvGrid, tableFeatures, type GridColumns } from '@svgrid/grid'

  type Row = { date: string; channel: string; device: string; signups: number; revenue: number }

  // 45 days x 3 channels x 2 devices, with a growth trend + weekly wobble + a spike.
  const CHANNELS = ['Organic', 'Paid', 'Referral']
  const DEVICES = ['Desktop', 'Mobile']
  const base: Record<string, number> = { Organic: 120, Paid: 80, Referral: 40 }
  const rows0: Row[] = []
  for (let d = 0; d < 45; d++) {
    const date = new Date(Date.UTC(2026, 0, 1 + d)).toISOString().slice(0, 10)
    const weekend = (d % 7 === 5 || d % 7 === 6) ? 0.7 : 1
    const spike = d === 30 ? 4 : 1 // launch-day spike -> log scale earns its keep
    for (const channel of CHANNELS) {
      for (const device of DEVICES) {
        const trend = 1 + d * 0.05
        const signups = Math.round(base[channel]! * trend * weekend * spike * (device === 'Mobile' ? 0.6 : 1))
        rows0.push({ date, channel, device, signups, revenue: signups * 12 })
      }
    }
  }

  let rows = $state<Row[]>(rows0)
  const features = tableFeatures({})

  const columns: GridColumns<Row> = [
    { field: 'date', header: 'Date', width: 120, cellDataType: 'date' },
    { field: 'channel', header: 'Channel', width: 120 },
    { field: 'device', header: 'Device', width: 110 },
    { field: 'signups', header: 'Signups', width: 110, align: 'right', cellDataType: 'number', format: { type: 'number', options: { maximumFractionDigits: 0 } } },
    { field: 'revenue', header: 'Revenue', width: 130, align: 'right', cellDataType: 'number', format: { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } },
  ]
</script>

<div class="demo-page" style="height: 620px; display: flex; flex-direction: column;">
  <p class="demo-lede">
    A daily signups sheet charted <strong>by date</strong>. The group-by column is a real date, so the
    <strong>Chart</strong> panel adds a <strong>Date axis</strong> toggle (proportional time gaps + date ticks)
    next to <strong>Log scale</strong>. Toggle either live, change the pickers, or filter the grid.
  </p>
  <div style="flex: 1; min-height: 0;">
    <SvGrid
      columnResize
      data={rows}
      columns={columns}
      features={features}
      selectionMode="cell"
      containerHeight="100%"
      charting={{
        defaultOpen: true,
        width: 520,
        defaultType: 'line',
        dimension: 'date',
        series: 'channel',
        measures: 'signups',
        timeAxis: true,
      }}
    />
  </div>
</div>

View this example on GitHub

Related documentation

Related articles

  • Immutable Grid Updates Without Killing Performance - Surgical immutability - how to get predictable reactivity in SvGrid without the cost of cloning everything on every change.
  • Immutable Data Updates in Svelte 5 - Svelte 5 runes track both mutation and reassignment, but for grids and lists, the way you update data determines whether re-renders are surgical or wasteful. Here are the patterns that actually hold up.
  • 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.

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.