Isomer charts

@elastic/isomer-primitives-charts is the published chart pack. It holds separate primitives per chart family over one shared core, a grid that lays nodes out as a Kibana dashboard does, and an unsupported placeholder for anything that cannot be shown.

A chart node is self-contained: its data is inline and typed, its data colors are concrete for both color schemes, and its formats come from one closed portable set. Whoever builds the node, a Kibana materializer or an agent, resolves everything a renderer would otherwise have to decide. Renderers translate; they never format, pick a data color, sort, or choose ticks.

Primitive Holds
metric One headline value, or one tile per row, with an optional secondary value, progress bar or trend line
xyChart Lines, areas and bars over a shared x axis, with reference lines and annotations
grid Titled panels on a 48-column grid, in optional sections
unsupported A visible placeholder with a reason and a link

Every chart primitive shares the chart core: title, description, data, colors, source and losses, and declares its interactions.

Entry Holds
@elastic/isomer-primitives-charts/schema The contracts: Zod schemas, node types, catalog entries and named examples. It imports no renderer.
@elastic/isomer-primitives-charts/scene The Scene types every renderer reads, and the SceneRenderer interface.
@elastic/isomer-primitives-charts Everything above.
import {
  metricExamples,
  metricSchema,
  type MetricNode,
} from '@elastic/isomer-primitives-charts/schema';
		

The schemas are object schemas for definePrimitive, which adds id and surfaces and closes each node to unknown keys; grid is a container and is bound to a composition's body-node union through gridSchemaFor. Validate a node inside a composition with a runtime that registers the pack, so nested nodes are checked against every pack the composition holds.

A chart node carries everything a faithful rendering needs, and drawing it is the engine's job. When a chart does not match its source, that is a gap in an engine, never missing information in the node. A field belongs on a primitive when:

  • It says what it draws, in Isomer's terms. Its description gives the values, units and effect a reader can check, never "as Lens does". A name borrowed from a source, such as an Elastic Charts fit or an EUI icon, is fine once the field defines it.
  • It carries what a faithful rendering needs, even if one engine alone can draw it. An engine that cannot draw a field documents its fallback; the field stays.
  • An agent can choose it from the catalog alone, without knowing the product a node may come from.
  • Its default is Isomer's. A materializer states its source's value rather than relying on the default to match.
  • A renderer reads it. What only a host acts on, such as a saved object id, belongs in opaque source meta.

z.toJSONSchema drops refinements, so each cross-field rule is stated word for word in the description an agent reads, and a test checks that each check states its rule there. The rules are on each primitive's page.