React axis components for data visualization with D3 scale integration, providing pre-built orientations and flexible customization options.
—
The flexible base Axis component provides complete control over axis orientation and behavior. Use this component when you need custom orientations, advanced styling, or when the pre-built components don't meet your specific requirements.
function Axis<Scale extends AxisScale>(props: AxisProps<Scale>): JSX.Element;
interface AxisProps<Scale extends AxisScale> extends SharedAxisProps<Scale> {
orientation?: OrientationType;
}
type OrientationType = "top" | "left" | "right" | "bottom";The Axis component extends SharedAxisProps with an additional orientation prop that determines axis direction and default styling.
import { Axis, Orientation } from '@visx/axis';
import { scaleLinear } from '@visx/scale';
const scale = scaleLinear({
range: [0, 400],
domain: [0, 100],
});
<Axis
scale={scale}
orientation={Orientation.bottom}
left={50}
top={300}
label="X Values"
stroke="#333"
tickStroke="#333"
tickLabelProps={{
fill: '#333',
fontSize: 11,
textAnchor: 'middle',
}}
/>The orientation prop accepts values from the Orientation constant:
const Orientation: {
readonly top: "top";
readonly left: "left";
readonly right: "right";
readonly bottom: "bottom";
};Each orientation automatically configures:
// Horizontal axes
<Axis orientation={Orientation.top} scale={xScale} /> // Ticks above, labels above ticks
<Axis orientation={Orientation.bottom} scale={xScale} /> // Ticks below, labels below ticks
// Vertical axes
<Axis orientation={Orientation.left} scale={yScale} /> // Ticks left, labels left of ticks
<Axis orientation={Orientation.right} scale={yScale} /> // Ticks right, labels right of ticksUse the children prop to provide a custom renderer function for complete control over axis rendering:
<Axis
scale={scale}
orientation={Orientation.bottom}
>
{(axisProps) => (
<g className="custom-axis">
{/* Custom axis line */}
<line
x1={axisProps.axisFromPoint.x}
y1={axisProps.axisFromPoint.y}
x2={axisProps.axisToPoint.x}
y2={axisProps.axisToPoint.y}
stroke="blue"
strokeWidth={2}
/>
{/* Custom ticks */}
{axisProps.ticks.map((tick, i) => (
<g key={i} className="custom-tick">
<line
x1={tick.from.x}
y1={tick.from.y}
x2={tick.to.x}
y2={tick.to.y}
stroke="red"
/>
<text
x={tick.from.x}
y={tick.from.y + 15}
textAnchor="middle"
fill="red"
>
{tick.formattedValue}
</text>
</g>
))}
</g>
)}
</Axis>Override individual tick rendering:
<Axis
scale={scale}
orientation={Orientation.bottom}
tickComponent={({ x, y, formattedValue }) => (
<g>
<circle cx={x} cy={y - 5} r={3} fill="red" />
<text x={x} y={y + 15} textAnchor="middle" fill="red">
{formattedValue}
</text>
</g>
)}
/>Override the entire tick rendering system:
<Axis
scale={scale}
orientation={Orientation.left}
ticksComponent={(ticksProps) => (
<g className="custom-ticks">
{ticksProps.ticks.map((tick, i) => (
<g key={i}>
<rect
x={tick.from.x - 20}
y={tick.from.y - 5}
width={15}
height={10}
fill="lightblue"
/>
<text
x={tick.from.x - 25}
y={tick.from.y + 3}
textAnchor="end"
fontSize={10}
>
{tick.formattedValue}
</text>
</g>
))}
</g>
)}
/>When using custom renderers, you receive AxisRendererProps:
interface AxisRendererProps<Scale extends AxisScale> extends SharedAxisProps<Scale> {
// Computed axis line endpoints
axisFromPoint: { x: number; y: number };
axisToPoint: { x: number; y: number };
// Axis configuration
horizontal: boolean;
orientation: OrientationType;
// Tick configuration
tickPosition: (value: ScaleInput<Scale>) => AxisScaleOutput;
tickSign: 1 | -1;
ticks: ComputedTick<Scale>[];
}
interface ComputedTick<Scale extends AxisScale> {
value: ScaleInput<Scale>;
index: number;
from: { x: number; y: number };
to: { x: number; y: number };
formattedValue: string | undefined;
}function ComplexChart() {
const xScale = scaleLinear({ range: [0, 400], domain: [0, 100] });
const yScale = scaleLinear({ range: [300, 0], domain: [0, 50] });
const y2Scale = scaleLinear({ range: [300, 0], domain: [0, 1000] });
return (
<svg width={500} height={350}>
{/* Primary Y axis */}
<Axis
scale={yScale}
orientation={Orientation.left}
left={40}
label="Primary Y"
stroke="#333"
/>
{/* Secondary Y axis */}
<Axis
scale={y2Scale}
orientation={Orientation.right}
left={440}
label="Secondary Y"
stroke="#666"
tickStroke="#666"
tickLabelProps={{ fill: '#666' }}
/>
{/* X axis */}
<Axis
scale={xScale}
orientation={Orientation.bottom}
top={300}
left={40}
label="X Values"
stroke="#333"
/>
</svg>
);
}// Custom diagonal axis using transform
<Axis
scale={scale}
orientation={Orientation.bottom}
tickTransform="rotate(-45)"
tickLabelProps={{
textAnchor: 'end',
dx: '-0.5em',
dy: '-0.25em'
}}
/>function ResponsiveAxis({ width, data }) {
const scale = scaleLinear({
range: [0, width],
domain: extent(data),
});
// Adjust tick count based on width
const numTicks = Math.max(2, Math.floor(width / 80));
return (
<Axis
scale={scale}
orientation={Orientation.bottom}
numTicks={numTicks}
tickLabelProps={{
fontSize: width < 400 ? 10 : 12,
}}
/>
);
}Install with Tessl CLI
npx tessl i tessl/npm-visx--axis