Skip to main content
Gremorie

Chart (bar)

Bar chart artifact rendering a schema-driven dataset emitted by the model.

Overview

A chart artifact that turns a small JSON payload into a real bar chart. The model emits an array of { category, value } rows plus a config that names the series and binds it to a chart token color. The artifact validates the payload, renders a BarChart from @gremorie/rx-data, and exposes an accessible data table for screen readers.

This is the canonical example of "schema in, UI out" — the model designs the dataset, the artifact handles axes, ticks, layout, and accessibility.

Preview

Quarterly revenue
Generated from a chart schema returned by the LLM.
JSON Schema
Bar chart of Revenue by category
categoryRevenue
Q142000
Q251000
Q348000
Q462000
Schema
{
  type: "chart-bar",
  data: Array<{ category: string; value: number }>,
  config: { xKey: string; yKey: string; label: string },
}

Schema

The LLM returns structured output matching this shape:

{
  type: "chart-bar",
  data: Array<{ category: string; value: number }>,
  config: { xKey: string; yKey: string; label: string },
}

Anatomy

Card
├─ CardHeader            CardTitle + Badge (outline) — artifact type
├─ BarChart (rx-data)    renders the dataset; ChartConfig maps value key → label + color token
└─ schema preview card   exposes the contract for inspection

Installation

npx gremorie@latest add artifact-chart-bar
pnpm dlx gremorie@latest add artifact-chart-bar
yarn dlx gremorie@latest add artifact-chart-bar
bunx --bun gremorie@latest add artifact-chart-bar

Prompt examples

Sample prompts that produce valid output for this artifact:

  • "Show me Q3 revenue by region as a bar chart."
  • "Compare monthly active users for the last 6 months."
  • "Plot ticket counts by priority bucket."

Code

'use client';

import {
  Badge,
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@gremorie/rx-display';
import { BarChart, type ChartConfig, type ChartDatum } from '@gremorie/rx-data';

const SCHEMA = `{
  type: "chart-bar",
  data: Array<{ category: string; value: number }>,
  config: { xKey: string; yKey: string; label: string },
}`;

const DATA: ChartDatum[] = [
  { category: 'Q1', value: 42000 },
  { category: 'Q2', value: 51000 },
  { category: 'Q3', value: 48000 },
  { category: 'Q4', value: 62000 },
];

const CONFIG: ChartConfig = {
  value: { label: 'Revenue', color: 'var(--chart-1)' },
};

export function ChartBar() {
  return (
    <div className="flex w-full flex-col gap-4">
      <Card>
        <CardHeader>
          <div className="flex items-center justify-between gap-3">
            <div>
              <CardTitle>Quarterly revenue</CardTitle>
              <CardDescription>
                Generated from a chart schema returned by the LLM.
              </CardDescription>
            </div>
            <Badge variant="outline">JSON Schema</Badge>
          </div>
        </CardHeader>
        <CardContent>
          <BarChart data={DATA} config={CONFIG} xKey="category" />
        </CardContent>
      </Card>
      <Card className="bg-muted/30">
        <CardHeader>
          <CardTitle className="text-sm">Schema</CardTitle>
        </CardHeader>
        <CardContent>
          <pre className="overflow-x-auto text-xs font-mono text-muted-foreground">
            {SCHEMA}
          </pre>
        </CardContent>
      </Card>
    </div>
  );
}

The Angular edition ships the ChartArtifact shell from @gremorie/ng-artifacts, which wraps any @gremorie/ng-data chart with a chart ⇄ table toggle and PNG / CSV downloads, plus the same accessible data table:

import { Component } from '@angular/core';
import { ChartArtifact } from '@gremorie/ng-artifacts';

@Component({
  selector: 'app-chart-bar',
  imports: [ChartArtifact],
  template: `
    <chart-artifact
      title="Quarterly revenue"
      description="Generated from a chart schema returned by the LLM."
      type="bar"
      categoryKey="category"
      valueKey="value"
      valueLabel="Revenue"
      [data]="data"
    />
  `,
})
export class ChartBarComponent {
  readonly data = [
    { category: 'Q1', value: 42000 },
    { category: 'Q2', value: 51000 },
    { category: 'Q3', value: 48000 },
    { category: 'Q4', value: 62000 },
  ];
}

Pass type (bar | area | line | pie | radar | radial | scatter) to switch the embedded chart, or a valueKey array for multi-series. The shell mirrors the React ChartArtifact input for input.

ChartArtifact props

Generated from the agnostic component contract (@gremorie/contracts), so the React and Angular editions and this table never drift:

PropTypeDefaultDescription
title*string-Single-line heading.
descriptionstring-Optional supporting line (truncates).
data*ChartArtifactDatum[]-Tabular rows: one object per category / point.
type'bar' | 'area' | 'line' | 'pie' | 'radar' | 'radial' | 'scatter''bar'Which chart primitive to embed.
categoryKey*string-Category / X field.
valueKey*string | ChartArtifactSeries[]-Value field(s): a string for one series, or a series array for multi-series.
categoryLabelstring-Header label for the category column.
valueLabelstring-Label for a single value series.
defaultView'chart' | 'table''chart'Which view is shown first.
numberFormatIntl.NumberFormatOptions-Number formatting for the table, CSV and tooltip.
fileNamestring'chart'Base name for downloads.
iconLucideIcon-Featured icon in the header.
accent'primary' | 'gray' | 'success' | 'error''primary'Featured-icon color.
classNamestring-Merged onto the card surface.
onRegenerate() => void-Wired to the Regenerate item.
onSave() => void-Wired to the Save item.

Streaming behavior

This artifact renders after the JSON payload parses. Partial payloads are deferred until data is a valid array — the chart never renders half a dataset.

On this page