Axis Overrides
This demo shows how XAxis and YAxis component children can override the inferred axis titles, bounds, ticks, tick formatting, and SVG classes in a CartesianChart component.
Boilerplate
First, we create the import aliases for TinyBase and React modules we'll need:
<script type="importmap">
{
"imports": {
"tinybase": "https://esm.sh/tinybase@8.5.0-beta.4",
"tinybase/ui-react": "https://esm.sh/tinybase@8.5.0-beta.4/ui-react",
"tinybase/ui-react-dom-charts": "https://esm.sh/tinybase@8.5.0-beta.4/ui-react-dom-charts",
"react": "https://esm.sh/react@^19.2.7",
"react/jsx-runtime": "https://esm.sh/react@^19.2.7/jsx-runtime",
"react-dom/client": "https://esm.sh/react-dom@^19.2.7/client"
}
}
</script>
We need a Store, a Provider, and the composable chart components:
import React from 'react';
import {createRoot} from 'react-dom/client';
import {createStore} from 'tinybase';
import {Provider, useCreateStore} from 'tinybase/ui-react';
import {
CartesianChart,
LineSeries,
XAxis,
YAxis,
} from 'tinybase/ui-react-dom-charts';
The App
The Store keeps dates as Unix second timestamps. The XAxis component marks them as a time scale and formats the Date objects it receives:
const timestamp = (day) => Date.UTC(2026, 0, day) / 1000;
const formatDate = (date) =>
date.toLocaleDateString('en-US', {
day: 'numeric',
month: 'short',
timeZone: 'UTC',
});
const App = () => {
const store = useCreateStore(() =>
createStore().setTable('sales', {
d1: {date: timestamp(1), revenue: 18},
d2: {date: timestamp(2), revenue: 26},
d3: {date: timestamp(3), revenue: 22},
d4: {date: timestamp(4), revenue: 39},
d5: {date: timestamp(5), revenue: 44},
d6: {date: timestamp(6), revenue: 41},
d7: {date: timestamp(7), revenue: 53},
}),
);
return (
<Provider store={store}>
<Body />
</Provider>
);
};
addEventListener('load', () => createRoot(document.body).render(<App />));
The Chart
The axis components are configuration children. They do not render separate charts; instead they tell the parent CartesianChart component how to render its shared axes:
const Body = () => (
<main>
<CartesianChart className="chart chart-axes" tableId="sales">
<XAxis
className="axis-dates"
max={timestamp(7)}
min={timestamp(1)}
scale="time"
tickFormatter={formatDate}
ticks={[timestamp(1), timestamp(3), timestamp(5), timestamp(7)]}
timestampUnit="second"
title="Sale date"
/>
<YAxis
className="axis-revenue"
max={60}
min={0}
tickFormatter={(tick) => `$${tick}k`}
ticks={[0, 20, 40, 60]}
title="Revenue"
/>
<LineSeries xCellId="date" yCellId="revenue" />
</CartesianChart>
</main>
);
Styling
Because the axis components add their className values to the x-axis and y-axis SVG groups, CSS can style them independently:
@font-face {
font-family: Inter;
src: url(https://tinybase.org/fonts/inter.woff2) format('woff2');
}
* {
box-sizing: border-box;
}
body {
background: white;
font-family: Inter, sans-serif;
margin: 0;
}
main {
margin: 2rem auto;
max-width: 52rem;
padding: 0 2rem;
}
.chart {
background: #f7f9fb;
border: 1px solid #dce5ee;
border-radius: 0.5rem;
color: #596779;
display: block;
font-size: 12px;
height: 20rem;
padding: 1rem;
width: 100%;
.grid {
color: #d7e0ea;
stroke-dasharray: 4 6;
}
.axes {
.title {
fill: #1f2937;
font-weight: 700;
}
}
.axis-dates {
fill: #275f83;
}
.axis-revenue {
fill: #6f4a1c;
}
.area {
fill: #3b82a0;
fill-opacity: 0.12;
}
.line {
stroke: #1f7799;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 3;
}
.points {
fill: white;
stroke: #1f7799;
stroke-width: 2;
}
}
@media (max-width: 40rem) {
main {
padding: 0 1rem;
}
}
Axis components make formatting and bounds explicit, while the series stays focused on data binding.