Customization
Charts
Data visualization with Unovis — a framework-agnostic charting library.
Why Unovis
Haze Dashboard uses Unovis for all charts. Unovis is framework-agnostic — the same data models and accessor functions work across @unovis/react, @unovis/svelte, and @unovis/angular. This makes your chart code portable.
SSR: Disable Server Rendering
Unovis renders to SVG/Canvas and requires the DOM. Since Next.js renders pages on the server by default, you must either mark chart components 'use client' and import them via next/dynamic with ssr: false, or lazy-load them at runtime:
'use client'
import dynamic from 'next/dynamic'
// Lazy-load chart components (unovis needs the DOM)
const RevenueChart = dynamic(() => import('./RevenueChart'), {
ssr: false,
loading: () => (
<div className="h-[300px] animate-pulse rounded-lg bg-[var(--haze-surface-hover)]" />
),
})
export default function Dashboard() {
return <RevenueChart />
}The loading placeholder prevents layout shifts and gives users immediate visual feedback while the chart hydrates.
Available Chart Types
| Type | Components | Use Case |
|---|---|---|
| Line | VisXYContainer + VisLine | Trends over time |
| Area | VisXYContainer + VisArea | Filled trend lines |
| Bar | VisXYContainer + VisGroupedBar | Category comparison |
| Stacked Bar | VisXYContainer + VisStackedBar | Part-to-whole by category |
| Donut | VisSingleContainer + VisDonut | Proportions |
| Scatter | VisXYContainer + VisScatter | Correlation analysis |
Example: Line Chart
A complete line chart with X and Y axes. The x and y props accept accessor functions that map your data shape to chart coordinates:
'use client'
import { VisXYContainer, VisLine, VisAxis } from '@unovis/react'
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
const data = [
{ month: 'Jan', revenue: 4200 },
{ month: 'Feb', revenue: 5800 },
{ month: 'Mar', revenue: 7200 },
{ month: 'Apr', revenue: 6100 },
{ month: 'May', revenue: 8400 },
{ month: 'Jun', revenue: 9200 },
]
export default function RevenueChart() {
return (
<VisXYContainer data={data} height={300}>
<VisLine
x={(_d, i) => i}
y={(d) => d.revenue}
color="var(--haze-primary)"
curveType="monotoneX"
/>
<VisAxis type="x" tickFormat={(i) => months[i as number]} />
<VisAxis type="y" tickFormat={(v) => '$' + v} />
</VisXYContainer>
)
}Example: Donut Chart
Donut charts use VisSingleContainer instead of VisXYContainer:
'use client'
import { VisSingleContainer, VisDonut } from '@unovis/react'
const colors = ['#14b8a6', '#3b82f6', '#f97316', '#8b5cf6']
const data = [
{ label: 'Desktop', value: 62 },
{ label: 'Mobile', value: 28 },
{ label: 'Tablet', value: 7 },
{ label: 'Other', value: 3 },
]
export default function TrafficDonut() {
return (
<VisSingleContainer data={data} height={250}>
<VisDonut
value={(d) => d.value}
arcWidth={40}
padAngle={0.02}
color={(_d, i) => colors[i]}
/>
</VisSingleContainer>
)
}Example: Area Chart
Area charts work exactly like line charts but fill the area below the line. You can combine multiple area layers for comparison:
'use client'
import { VisXYContainer, VisArea, VisLine, VisAxis } from '@unovis/react'
const data = [
{ users: 120 }, { users: 180 }, { users: 240 },
{ users: 310 }, { users: 280 }, { users: 390 },
]
export default function UsersChart() {
return (
<VisXYContainer data={data} height={250}>
<VisArea
x={(_d, i) => i}
y={(d) => d.users}
color="var(--haze-primary)"
opacity={0.3}
curveType="monotoneX"
/>
<VisLine
x={(_d, i) => i}
y={(d) => d.users}
color="var(--haze-primary)"
/>
<VisAxis type="x" />
<VisAxis type="y" />
</VisXYContainer>
)
}Accessor Functions
Unovis uses accessor functions to decouple chart components from your data shape. Instead of requiring specific property names, you provide a function that extracts the value:
// Accessor functions extract values from your data
const xAccessor = (d: DataPoint, i: number) => i // Use index as x
const yAccessor = (d: DataPoint) => d.revenue // Use revenue as y
const colorAccessor = (d: DataPoint) => d.color // Per-item color
// These are passed as props:
// <VisLine x={xAccessor} y={yAccessor} color={colorAccessor} />Styling Charts
Use the design system's CSS custom properties for consistent chart colors:
// Use CSS variables for consistent theming
<VisLine
x={(_d, i) => i}
y={(d) => d.value}
color="var(--haze-primary)"
/>
// Multiple series with different colors
<VisLine x={xAccessor} y={(d) => d.revenue} color="#14b8a6" />
<VisLine x={xAccessor} y={(d) => d.expenses} color="#f97316" />Adding a Chart to a Page
Follow these steps to add a new chart:
- Prepare your data array (from an API route, server component, or static data)
- Define accessor functions for the x and y axes
- Create a client component (
'use client') for the chart - Lazy-load it from the parent page via
next/dynamicwithssr: false - Set a height on the container
Tip
Unovis configs are portable — the same data structures and accessor functions work identically in @unovis/react, @unovis/svelte, and @unovis/angular. Only the JSX syntax changes.
Next Steps
Learn about multi-language support in the Internationalization guide.