Compare three totals in React, inspect their exact values, and verify the server-rendered bar geometry.
Compare categories and keep a usable route to the values when the picture is unavailable.
Data needed:One already aggregated, nonnegative total per category, all in the same unit. The synthetic fixture is North 12, South 30, West 18.
Source checkout · Semiotic 3.9.2. Check the installed version before applying this guide.
When this fits
- Use in an existing Semiotic React application or when structured chart access and schema-guided validation meet an explicit project requirement.
- A small chart change alone need not justify replacing a working visualization library.
- This fixture does not establish that an external source is accurate or that every reader can use the result.
Try the complete example
Synthetic fixture: three already aggregated regional totals, all measured in units.
South has the largest total, 30. The three regions total 60 units. Open the data table for exact values.
South accounts for 30 of the 60 units. Changing direction preserves the values and category order.
Use it in your application
BarChart from semiotic/ordinal, instatic mode.
React component · React browser
Save as CategoryComparisonExample.tsx beside its companion files below.
TSX
import { useState } from "react" import { BarChart } from "semiotic/ordinal" import { categoryComparisonProps } from "./category-comparison" export default function CategoryComparisonExample() { const [orientation, setOrientation] = useState<"vertical" | "horizontal">("vertical") return ( <section aria-label="Category comparison example" className="task-example"> <p>Synthetic fixture: three already aggregated regional totals, all measured in units.</p> <label> Bar direction{" "} <select value={orientation} onChange={(event) => setOrientation(event.target.value as typeof orientation)} > <option value="vertical">Vertical</option> <option value="horizontal">Horizontal</option> </select> </label> <BarChart {...categoryComparisonProps} orientation={orientation} responsiveWidth /> <p> South accounts for 30 of the 60 units. Changing direction preserves the values and category order. </p> </section> ) }
Shared fixture and chart props · Browser and server
Save as category-comparison.ts beside its companion files below.
TSX
import type { BarChartProps } from "semiotic/ordinal" export const regionalTotals = [ { region: "North", total: 12 }, { region: "South", total: 30 }, { region: "West", total: 18 }, ] export const categoryComparisonProps = { data: regionalTotals, categoryAccessor: "region", valueAccessor: "total", sort: false, title: "Regional totals", description: "Synthetic regional totals in the same unit: North 12, South 30, West 18.", summary: "South has the largest total, 30. The three regions total 60 units. Open the data table for exact values.", accessibleTable: true, valueLabel: "Units", height: 300, } satisfies BarChartProps<(typeof regionalTotals)[number]>
Optional server verification · Node authoring only
Save as check-category-comparison.ts beside its companion files below.
TSX
// Server-side authoring only: keep validation and SVG rendering out of the React route. import { prepareChart } from "semiotic/ai/core" import { renderChartWithEvidence } from "semiotic/server" import { categoryComparisonProps } from "./category-comparison" export function checkCategoryComparison() { const result = prepareChart( { component: "BarChart", props: categoryComparisonProps }, { render: renderChartWithEvidence }, ) if (!result.ok || !result.evidence || !result.svg) { throw new Error(result.reasons.join("; ") || "Render evidence is unavailable") } return result }
Check the result
Repository source checks passed on 2026-09-07T19:35:59.815Z.
- North 12, South 30, West 18; total 60, with South largest.
- Three SVG bars retain 12:30:18 proportions and insertion order in both orientations.
- The browser data table retains the exact category/value mapping.
- An invalid value accessor is refused; the repaired configuration preserves the rows.
BASH
npx vitest run docs/src/pages/tasks/examples/category-comparison.test.ts npx playwright test --config playwright.docs-examples.config.ts integration-tests/docs-examples-tasks.spec.ts
These checks leave the following questions open:
- Underlying source accuracy: this is a synthetic fixture.
- Assistive-technology reception and usability with actual readers.
- Organic discovery, model preference, and published-package parity.
Repair and recheck
The chart has no useful values after a field was renamed.
Set valueAccessor to the actual numeric field, total, while preserving data. Run the server check and inspect the exact-value table.
Recheck:The bars must encode 12, 30 and 18; a nonempty scene alone is insufficient.
Behavior contract: props.data-required-by-usage-mode
prepareChart returned ok, but there is no SVG.
Inject renderChartWithEvidence from semiotic/server in Node authoring code when rendered evidence is required.
Recheck:Inspect evidence and svg explicitly. Without a renderer, ok covers a different set of checks.
Behavior contract: rendering.renderchart-static-props
Leave useful maintenance context
This project needs React rendering with inspectable category values.
- Category/value mapping, units, order, summary and the accessible table after source or dependency changes.
An image alone omits the source rows and verification context. Keep the config and fixture when the next reader needs exact values.
Keep project notes optional. A changed requirement or dependency policy can justify a different approach.
What to recheck after an update
Current source guidance; an installed-release introduction has not been established.
Assumption to revisit:A valid configuration or a nonempty render establishes that the values are mapped correctly.
Run configuration checks, inspect the rendered geometry and compare the category/value table with independent fixture facts.
- Rendering evidence must be present when a render is claimed.
- An installed package version different from the packet's packageVersion needs matching guidance.
Source truth and usability with actual readers remain separate obligations.
Inspect exact API, source identity and mode rules
Verified source checkout guidance; npm package, hosted site and MCP deployment identities require separate checks.
Content revision: sha256:50e44656b1e17407ddafb6f64b051443a1a314a5f679e35a52cb1c975131d0c2
Selected properties copied from ai/schema.json; retrieve the component resource for the full schema. React push mode follows the included behavior contracts. Full resource: semiotic://schema/BarChart.
JSON
{ "type": "object", "properties": { "data": { "type": "array", "description": "Array of data objects" }, "categoryAccessor": { "type": "string", "description": "Key for category labels", "default": "category", "x-semiotic-runtime-types": [ "string", "function" ] }, "valueAccessor": { "type": "string", "description": "Key for bar values", "default": "value", "x-semiotic-runtime-types": [ "string", "function" ] }, "sort": { "type": [ "boolean", "string" ], "description": "Sort bars: false, true, 'asc', 'desc', or comparator function", "default": false, "x-semiotic-runtime-types": [ "boolean", "string", "function" ] }, "orientation": { "type": "string", "enum": [ "vertical", "horizontal" ], "default": "vertical" }, "title": { "type": "string", "description": "Visible chart title and the chart's accessible name." }, "description": { "type": "string", "description": "Concise accessible description that overrides the chart's generated aria-label." }, "summary": { "type": "string", "description": "Screen-reader-only summary of the chart's key takeaway; include keyboard interaction guidance when relevant." }, "accessibleTable": { "type": [ "boolean", "object" ], "description": "Expose the chart data through Semiotic's screen-reader data table. Object form `{ portalTarget: string }` relocates its interactive UI to the DOM element with that ID.", "default": true, "oneOf": [ { "type": "boolean" }, { "type": "object", "additionalProperties": false, "required": [ "portalTarget" ], "properties": { "portalTarget": { "type": "string", "description": "ID of a DOM element outside any consumer-owned role=img wrapper. React callers may also pass an Element or a callback through the typed API." } } } ] }, "height": { "type": "number", "default": 400 }, "responsiveWidth": { "type": "boolean" }, "valueLabel": { "type": "string" } }, "requiredForStatic": [ "data" ] }
accessibility.description-props: High-level charts expose title for the visible name, description for a concise accessible description, summary for a screen-reader-only takeaway and interaction guidance, and accessibleTable for the data-table fallback.Put title, description, summary, and accessibleTable directly on the chart component when they appear in its schema. If a consumer-owned role=img wraps the chart, use accessibleTable: { portalTarget: "element-id" } and render that target outside the image. For generated L1–L3 description or a navigable chart tree, use ChartContainer with chartConfig plus describe and/or navigable; do not invent frameProps fields.props.data-required-by-usage-mode: Static usage (`renderChart`, MCP previews, SSR snapshots, and copy/paste examples with immediate data) requires data in props. React push mode selects live ingestion by omitting data and mutating through a ref.Pass usageMode="push" to `semiotic-ai --doctor` when validating ref-based JSX with no data prop. Keep usageMode="static" or omit it for renderChart/MCP/static configs where data must be present.rendering.renderchart-static-props: MCP renderChart and semiotic/server renderChart render a single static SVG/PNG snapshot. Browser-only realtime components and future ref pushes are not renderable through that path.Use renderChart only with renderable HOC components and complete static data. For live behavior, return React code with a ref and do not promise MCP-rendered output.serialization.formatters-are-react-callbacks: xFormat, yFormat, categoryFormat, and valueFormat are callback props, not d3 format strings or axis-title strings. They are intentionally absent from JSON/MCP schemas and string values fail validation.In serialized props, omit formatter callbacks and use xLabel, yLabel, categoryLabel, or valueLabel for axis titles. In React JSX, pass a function such as xFormat={value => formatAxis(value)}.
Agent-observed execution of repository tests; independent review is not recorded.