> ## Documentation Index
> Fetch the complete documentation index at: https://docs.graphy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Data labels

Data labels print each observation's value directly on the observation. Unlike the other topics in this section, they're **not** a `config` field — they're a per-layer option on a [geom](/sdk-next/concepts/geoms), because a label attaches to a specific observation.

```tsx theme={null}
geom.bar({
  dataLabels: { showDataLabels: true },
});
```

## Options

<ParamField path="showDataLabels" type="boolean" default="false">
  Turn labels on for this layer. `geom.tile()` is the exception: a
  [heatmap](/sdk-next/graph-types/heatmap) is read cell by cell, so its labels
  start on and you turn them off instead.
</ParamField>

<ParamField path="format" type="'absolute' | 'percentage'" default="absolute">
  Show the raw value, or its share of the total.
</ParamField>

<ParamField path="position" type="'auto' | 'inside' | 'outside'" default="auto">
  Where the label sits relative to the observation. `'auto'` lets the engine
  fit, flip, rotate or drop labels as space allows — dropping, flipping and
  rotation happen under `'auto'` only. `'inside'` and `'outside'` render exactly
  as asked and are never dropped; stacked and filled cartesian bar segments
  coerce `'outside'` to `'inside'`, since every segment edge borders a neighbour
  (pie wedges keep `'outside'`).
</ParamField>

<ParamField path="justify" type="'start' | 'center' | 'end' | 'panel-start' | 'panel-end'" default="end ('center' for stacked/filled bars)">
  Anchor along the observation's value axis. `'end'` is the value tip whatever
  the orientation or sign. `'panel-start'` / `'panel-end'` resolve against the
  panel instead of the observation's box, so labels sit flush at the chart edge
  however long the geom is. Only consulted when `position` is explicit.
</ParamField>

<ParamField path="align" type="'start' | 'center' | 'end'" default="center">
  Anchor across the observation's other axis — bandwidth for bars, angular for
  wedges, x for points, lines and areas. Only consulted when `position` is
  explicit.
</ParamField>

<ParamField path="offset" type="number">
  Gap in pixels between the observation's edge and the label. Defaults to 4 for
  bars and wedges, 12 for points and lines. Stack totals ignore it.
</ParamField>

<ParamField path="showStackTotals" type="boolean" default="false">
  On stacked bars, print the stack total at the end of each stack.
</ParamField>

<ParamField path="showCategoryLabels" type="boolean" default="false">
  On polar bars (pie/donut) prepend the category to the value ("North · 35%").
  On cartesian bars, emit a second category label per bar — placed by the
  `category*` fields below, independently of `showDataLabels`. Other geoms
  ignore it.
</ParamField>

## Category labels

On cartesian bars the category label is placed by its own quartet, so it can sit at the base of the
bar while the value label sits at the tip:

```tsx theme={null}
geom.bar({
  dataLabels: {
    showDataLabels: true,
    showCategoryLabels: true,
    categoryPosition: 'inside',
    categoryJustify: 'start',
  },
});
```

<ParamField path="categoryPosition" type="'inside' | 'outside'" default="inside">
  Where the category label sits relative to its bar. There's no `'auto'` —
  category labels render exactly as asked. Stacked and filled segments coerce
  `'outside'` to `'inside'`.
</ParamField>

<ParamField path="categoryJustify" type="'start' | 'center' | 'end' | 'panel-start' | 'panel-end'" default="start">
  Anchor along the bar's value axis. Takes panel anchors like `justify`.
</ParamField>

<ParamField path="categoryAlign" type="'start' | 'center' | 'end'" default="center">
  Anchor across the bar's bandwidth.
</ParamField>

<ParamField path="categoryOffset" type="number" default="4">
  Gap in pixels between the anchored edge and the category label box.
</ParamField>

## Styling

This page places labels; the stylesheet paints them. Type, box padding, background, border and
corner radius come from the `dataLabel` target and its roles — `.observation` and `.category`, each
with an `.inside` and `.outside` variant, plus `.aggregate` for stack totals:

```tsx theme={null}
styles({
  defaults: [
    style.dataLabel({ fontSize: 11 }),
    style.dataLabel.observation.outside({ fill: '#FFFFFF', paddingInline: 4 }),
  ],
});
```

A label's effective position picks which variant applies: over the geom it takes inside styling
(white text, no background); off it — by placement, by offset, or because it didn't fit — it takes
outside styling. Area labels always use outside styling, because a translucent fill can't back white
text. See [Styling](/sdk-next/config/styling).

## Examples

Percentage labels on a pie's wedges, with the category name:

```tsx theme={null}
geom.bar({
  position: 'stack',
  dataLabels: {
    showDataLabels: true,
    format: 'percentage',
    showCategoryLabels: true,
  },
});
```

Totals at the top of each stacked column:

```tsx theme={null}
geom.bar({
  position: 'stack',
  dataLabels: { showDataLabels: true, showStackTotals: true },
});
```

## Related

* [Geoms & layers](/sdk-next/concepts/geoms) — where layer options live
* [Number format](/sdk-next/config/number-format) — how label values are formatted
* [Custom geoms](/sdk-next/extending/custom-geoms#data-labels) — how a geom of your own places its labels


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.