Plug in custom date libraries for timezone and locale support.
The timeline uses a date adapter for all date operations: parsing input dates, calculating tick positions, snapping to time boundaries, and formatting labels. By default, a built-in adapter using the browser's native Date object handles everything. If you need timezone-aware rendering or custom locale formatting, you can register a custom adapter that wraps a library like Luxon or Day.js.
The default adapter works out of the box with no configuration. It uses the browser's local timezone and supports the following format tokens for axis labels and tooltips:
| Token | Output | Example |
|---|---|---|
YYYY | Full year | 2026 |
MMMM | Full month name | January |
MMM | Short month name | Jan |
MM | Zero-padded month | 01 |
D | Day of month | 5 |
ddd | Short weekday | Mon |
HH | 24-hour hours | 14 |
hh | 12-hour hours | 02 |
mm | Minutes | 05 |
ss | Seconds | 03 |
SSS | Milliseconds | 007 |
A | Uppercase AM/PM | PM |
a | Lowercase am/pm | pm |
Tokens can be combined freely: "ddd D MMMM HH:mm" produces "Mon 5 January 14:05".
A custom adapter must implement four methods. All operate on epoch milliseconds internally.
| Method | Signature | Description |
|---|---|---|
parse | (input: string | number | Date) => number | null | Convert a date input (ISO string, timestamp, or Date object) into epoch milliseconds. Return null if the input is invalid. |
startOf | (instant: number, unit: string) => number | Snap a timestamp to the start of the given unit (e.g. "day", "month", "year"). Used to calculate tick positions on the time axis. |
add | (instant: number, unit: string, amount: number) => number | Add a number of calendar units to a timestamp. Supports negative amounts for subtraction. Used to step through ticks on the axis. |
format | (instant: number, pattern: string) => string | Format a timestamp into a display string using the pattern tokens. Used for axis labels and default tooltips. |
The startOf and add methods receive one of these unit strings:
year, month, week, day, hour, minute, second, millisecond
import { AdapterRegistry } from '@tempis/timeline';
AdapterRegistry.register(myAdapter);
This adapter renders all dates in the America/New_York timezone using Luxon:
import { DateTime } from 'luxon';
import { AdapterRegistry } from '@tempis/timeline';
import type { TempisTimelineDateAdapter } from '@tempis/timeline';
const luxonAdapter: TempisTimelineDateAdapter = {
parse(input) {
if (input instanceof Date) return input.getTime();
if (typeof input === 'number') return isNaN(input) ? null : input;
const dt = DateTime.fromISO(input, { zone: 'America/New_York' });
return dt.isValid ? dt.toMillis() : null;
},
startOf(instant, unit) {
return DateTime.fromMillis(instant, { zone: 'America/New_York' })
.startOf(unit as any)
.toMillis();
},
add(instant, unit, amount) {
return DateTime.fromMillis(instant, { zone: 'America/New_York' })
.plus({ [unit + 's']: amount })
.toMillis();
},
format(instant, pattern) {
// Luxon uses different tokens — map common ones.
const luxonPattern = pattern
.replace('YYYY', 'yyyy')
.replace('D', 'd')
.replace('ddd', 'EEE');
return DateTime.fromMillis(instant, { zone: 'America/New_York' })
.toFormat(luxonPattern);
}
};
// Register once at app startup.
AdapterRegistry.register(luxonAdapter);
format method should either map the Tempis tokens to your library's tokens, or configure the timeline's range.minorUnit.formats and range.majorUnit.formats to use your library's native token syntax.import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import { AdapterRegistry } from '@tempis/timeline';
import type { TempisTimelineDateAdapter } from '@tempis/timeline';
dayjs.extend(utc);
dayjs.extend(timezone);
const TZ = 'Europe/London';
const dayjsAdapter: TempisTimelineDateAdapter = {
parse(input) {
if (input instanceof Date) return input.getTime();
if (typeof input === 'number') return isNaN(input) ? null : input;
const d = dayjs.tz(input, TZ);
return d.isValid() ? d.valueOf() : null;
},
startOf(instant, unit) {
return dayjs(instant).tz(TZ).startOf(unit as any).valueOf();
},
add(instant, unit, amount) {
return dayjs(instant).tz(TZ).add(amount, unit as any).valueOf();
},
format(instant, pattern) {
return dayjs(instant).tz(TZ).format(pattern);
}
};
AdapterRegistry.register(dayjsAdapter);