Skip to content

Tick labels

categoryAxis.tickLabel controls the text drawn at each tick of the category axis: how it reads (format), which way it faces (rotation, anchor) and what happens when the labels need more room than the axis has. There are two ways out of that: cut the labels short, or draw fewer of them. Which one the axis takes depends on truncation.enabled and on whether the labels run along the axis or across it.

Value axes take the same tickLabel settings apart from the truncation ones (see valueAxes.tickLabel).

ts
// Long team names on a horizontal category axis. Rotating the labels -45°
// makes them perpendicular to the axis, so each one is truncated to a
// fraction of the plot height (truncation.maxFraction) rather than to the
// width of its category slot; truncation.minLength keeps a readable minimum
// when the chart is short.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Open Tickets by Team' },
  categoryAxis: {
    property: 'team',
    type: 'string',
    scale: 'ordinal',
    title: { text: 'Team' },
    tickLabel: {
      rotation: -45,
      truncation: { enabled: true, maxFraction: 0.35, minLength: 72, text: '…' }
    }
  },
  valueAxes: [{ id: 'VA0', title: { text: 'Open tickets' }, min: 0 }],
  series: [{ property: 'open', title: 'Open tickets', renderer: 'bar' }]
};

export const data = [
  { team: 'Customer Support (Americas)', open: 42 },
  { team: 'Customer Support (EMEA)', open: 37 },
  { team: 'Platform Engineering', open: 18 },
  { team: 'Mobile Applications', open: 25 },
  { team: 'Data and Analytics', open: 11 },
  { team: 'Billing and Payments', open: 29 },
  { team: 'Security Operations', open: 8 },
  { team: 'Developer Relations', open: 14 },
  { team: 'Quality Assurance', open: 21 }
];

How it works

  • rotation turns each label by -90° to 90°. On a horizontal axis the labels count as perpendicular to the axis once the rotation reaches 20° either way; on a vertical axis (a horizontal bar chart) flat labels are already perpendicular, and only a rotation past 70° lays them along the axis. Perpendicular labels take up their text height along the axis instead of their width, so more ticks fit.
  • truncation.enabled defaults to true on a string axis and false on number and date axes. When it is on, a label that does not fit is cut and truncation.text is appended. The room a label gets depends on its direction: a label running along the axis is clipped to the width of its category slot, so every category keeps a label; a perpendicular label may occupy up to truncation.maxFraction of the plot bounds (the plot height for a horizontal axis, its width for a vertical one), and never less than truncation.minLength pixels — that floor is what keeps the labels above legible on a short chart.
  • truncation.tooltipEnabled (on by default) gives each truncated label an svg <title> holding its full text, which browsers show as their native tooltip while a mouse or pen rests on the label. Touch has no hover, so nothing shows there; screen readers already get the full text through aria-label.
  • With truncation off, nothing is cut: the axis drops ticks until the remaining labels fit, as in the next example.
  • anchor sets which end of the text sits on the tick. The default auto centres labels that run along the axis and, for perpendicular ones, anchors the end nearest the axis — a -45° label ends at its tick and reads up towards it, a 45° one starts there and reads away. Set start, middle or end to override.
  • format is a d3-format string for number axes or a d3-time-format one for date axes; auto derives a format from the data and null shows the raw value.
  • size is the space reserved for the labels across the axis, auto measuring the rotated text. A fixed number keeps the plot the same height as the labels change.
  • textStyle styles the text in its normal, focused and defocusedstates; the default currentColor fill follows the host page's colour.
  • The marginInner / paddingInner pair spaces the labels from the plot side of the axis, and marginOuter / paddingOuter from the title side. Padding sits inside the label's backgroundStyle box, margin outside it.

Fewer ticks instead

When the labels are not truncated, the axis decides how many ticks it can show and hides the rest at a regular interval, so the labels that remain are drawn in full.

ts
// Thirty daily readings on an ordinal date axis. The labels stay flat and
// truncation is off, so the axis keeps only as many ticks as fit — one label
// width plus minTickSpacing per tick, at most maxTickCount — and draws the
// surviving labels in full. format sets the label text.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Daily Visits' },
  categoryAxis: {
    property: 'day',
    type: 'date',
    scale: 'ordinal',
    title: { text: 'June 2026' },
    minTickSpacing: 24,
    maxTickCount: 8,
    tickLabel: {
      format: '%b %d',
      truncation: { enabled: false },
      marginInner: 4,
      textStyle: { normal: { fillOpacity: 0.75 } }
    }
  },
  valueAxes: [{ id: 'VA0', title: { text: 'Visits' }, min: 0 }],
  series: [{ property: 'visits', title: 'Visits', renderer: 'area' }]
};

const firstDay = Date.UTC(2026, 5, 1);
const dayMs = 24 * 60 * 60 * 1000;

export const data = Array.from({ length: 30 }, (_, i) => ({
  day: new Date(firstDay + i * dayMs).toISOString(),
  // a weekly rhythm: weekends (June 2026 starts on a Monday) dip
  visits: Math.round(180 + 40 * Math.sin(i / 2.5) - (i % 7 >= 5 ? 60 : 0))
}));
  • tickCount defaults to auto: the axis divides its length by one label's extent along it (the widest label's width when flat, the text height when perpendicular) plus minTickSpacing, and keeps that many ticks. On an ordinal axis it keeps every nth category to get down to the count; on a linear axis it asks the scale for that many ticks. A number replaces the calculation outright.
  • maxTickCount caps the computed count — 10 on a linear axis, uncapped (0) on an ordinal one — so the eight ticks above are the cap, not the fit. On a linear axis minTickInterval also stops ticks landing closer together than a given value.
  • Rotation and truncation fit into the same count: a string axis with truncation on works out the count from the shortest label truncation can produce, which is why it keeps every category, and a rotated axis fits more ticks because each takes less room along the axis.

Released under the MIT License.