- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Form
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Menubar
- Native Select
- Navigation Menu
- Pagination
- Pin Input
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Stepper
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
- Typography
Bar Chart - Interactive
Showing total visitors for the last 3 months
Introducing Charts. A collection of chart components that you can copy and paste into your apps.
Charts are designed to look great out of the box. They work well with the other components and are fully customizable to fit your project.
Component
We use Unovis under the hood.
We designed the chart component with composition in mind. You build your charts using Unovis components and only bring in custom components, such as ChartTooltip, when and where you need it.
<script setup lang="ts">
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartTooltipContent } from '@/components/ui/chart'
</script>
<template>
<ChartContainer :config="chartConfig">
<VisXYContainer :data="data">
<VisGroupedBar :x="(d) => d.month" :y="(d) => d.value" />
<ChartTooltip :template="componentToString(chartConfig, ChartTooltipContent)" />
</VisXYContainer>
</ChartContainer>
</template>We do not wrap Unovis. This means you're not locked into an abstraction. When a new Unovis version is released, you can follow the official upgrade path to upgrade your charts.
The components are yours.
Installation
pnpm dlx shadcn-vue@latest add chart
Usage
<script setup lang="ts">
import type { ChartConfig } from '@/components/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import {
ChartContainer,
ChartCrosshair,
ChartTooltip,
ChartTooltipContent,
componentToString,
} from '@/components/ui/chart'
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'var(--chart-1)',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d) => d.month"
:y="(d) => d.desktop"
:color="chartConfig.desktop.color"
/>
<ChartTooltip />
<ChartCrosshair
:template="componentToString(chartConfig, ChartTooltipContent)"
/>
</VisXYContainer>
</ChartContainer>
</template>Your First Chart
Let's build your first chart. We'll build a bar chart, add a grid, axis, tooltip and legend.
Start by defining your data
The following data represents the number of desktop and mobile users for each month.
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
]Define your chart config
The chart config holds configuration for the chart. This is where you place human-readable strings, such as labels, icons and color tokens for theming.
import type { ChartConfig } from "@/components/ui/chart"
const chartConfig = {
desktop: {
label: "Desktop",
color: "var(--chart-1)",
},
mobile: {
label: "Mobile",
color: "var(--chart-2)",
},
} satisfies ChartConfigBuild your chart
You can now build your chart using Unovis components.
<script setup lang="ts">
import type { ChartConfig } from '@/registry/new-york-v4/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/registry/new-york-v4/ui/chart'
const chartData = [
{ date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
{ date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
{ date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
{ date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
{ date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
{ date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]
type Data = typeof chartData[number]
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d: Data) => d.date"
:y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
:rounded-corners="4"
bar-padding="0.1"
group-padding="0"
/>
</VisXYContainer>
</ChartContainer>
</template><script setup lang="ts">
import type { ChartConfig } from '@/registry/new-york-v4/ui/chart'
import { VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/registry/new-york-v4/ui/chart'
const chartData = [
{ date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
{ date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
{ date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
{ date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
{ date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
{ date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]
type Data = typeof chartData[number]
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d: Data) => d.date"
:y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
:rounded-corners="4"
bar-padding="0.1"
group-padding="0"
/>
</VisXYContainer>
</ChartContainer>
</template>Add an Axis
To add axes to the chart, we use the VisAxis component.
Import the VisAxis component
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'Add the VisAxis components to your chart
<template>
<VisAxis
type="x"
:x="(d: Data) => d.date"
:tick-line="false"
:domain-line="false"
:grid-line="false"
:tick-format="(d: number) => {
const date = new Date(d)
return date.toLocaleDateString('en-US', {
month: 'short',
})
}"
:tick-values="chartData.map(d => d.date)"
/>
<VisAxis
type="y"
:tick-format="(d: number) => ''"
:tick-line="false"
:domain-line="false"
:grid-line="true"
/>
</template><script setup lang="ts">
import type { ChartConfig } from '@/registry/new-york-v4/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer } from '@/registry/new-york-v4/ui/chart'
const chartData = [
{ date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
{ date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
{ date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
{ date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
{ date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
{ date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]
type Data = typeof chartData[number]
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d: Data) => d.date"
:y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
:rounded-corners="4"
bar-padding="0.1"
group-padding="0"
/>
<VisAxis
type="x"
:x="(d: Data) => d.date"
:tick-line="false"
:domain-line="false"
:grid-line="false"
:tick-format="(d: number) => {
const date = new Date(d)
return date.toLocaleDateString('en-US', {
month: 'short',
})
}"
:tick-values="chartData.map(d => d.date)"
/>
<VisAxis
type="y"
:tick-format="(d: number) => ''"
:tick-line="false"
:domain-line="false"
:grid-line="true"
/>
</VisXYContainer>
</ChartContainer>
</template>Add Tooltip
To add a tooltip, we'll use the custom ChartTooltip and ChartTooltipContent components from chart.
Import the ChartTooltip and ChartTooltipContent components
import { ChartTooltip, ChartTooltipContent, componentToString } from "@/components/ui/chart"Add the components to your chart
<ChartTooltip />
<ChartCrosshair :template="componentToString(chartConfig, ChartTooltipContent)" /><script setup lang="ts">
import type { ChartConfig } from '@/registry/new-york-v4/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartCrosshair, ChartTooltip, ChartTooltipContent, componentToString } from '@/registry/new-york-v4/ui/chart'
const chartData = [
{ date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
{ date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
{ date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
{ date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
{ date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
{ date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]
type Data = typeof chartData[number]
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d: Data) => d.date"
:y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
:rounded-corners="4"
bar-padding="0.1"
group-padding="0"
/>
<VisAxis
type="x"
:x="(d: Data) => d.date"
:tick-line="false"
:domain-line="false"
:grid-line="false"
:tick-format="(d: number) => {
const date = new Date(d)
return date.toLocaleDateString('en-US', {
month: 'short',
})
}"
:tick-values="chartData.map(d => d.date)"
/>
<VisAxis
type="y"
:tick-format="(d: number) => ''"
:tick-line="false"
:domain-line="false"
:grid-line="true"
/>
<ChartTooltip />
<ChartCrosshair
:template="componentToString(chartConfig, ChartTooltipContent, {
labelFormatter(d) {
return new Date(d).toLocaleDateString('en-US', {
month: 'long',
})
},
})"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
/>
</VisXYContainer>
</ChartContainer>
</template>Hover to see the tooltips. Easy, right? Two components, and we've got a beautiful tooltip.
Add Legend
We'll do the same for the legend. We'll use the ChartLegend and ChartLegendContent components from chart.
Import the ChartLegendContent components.
import { ChartLegendContent } from "@/components/ui/chart"Add the components to your chart.
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
</VisXYContainer>
<ChartLegendContent />
</ChartContainer>
</template><script setup lang="ts">
import type { ChartConfig } from '@/registry/new-york-v4/ui/chart'
import { VisAxis, VisGroupedBar, VisXYContainer } from '@unovis/vue'
import { ChartContainer, ChartCrosshair, ChartLegendContent, ChartTooltip, ChartTooltipContent, componentToString } from '@/registry/new-york-v4/ui/chart'
const chartData = [
{ date: new Date('2024-01-01'), desktop: 186, mobile: 80 },
{ date: new Date('2024-02-01'), desktop: 305, mobile: 200 },
{ date: new Date('2024-03-01'), desktop: 237, mobile: 120 },
{ date: new Date('2024-04-01'), desktop: 73, mobile: 190 },
{ date: new Date('2024-05-01'), desktop: 209, mobile: 130 },
{ date: new Date('2024-06-01'), desktop: 214, mobile: 140 },
]
type Data = typeof chartData[number]
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
</script>
<template>
<ChartContainer :config="chartConfig" class="min-h-[200px] w-full">
<VisXYContainer :data="chartData">
<VisGroupedBar
:x="(d: Data) => d.date"
:y="[(d: Data) => d.desktop, (d: Data) => d.mobile]"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
:rounded-corners="4"
bar-padding="0.1"
group-padding="0"
/>
<VisAxis
type="x"
:x="(d: Data) => d.date"
:tick-line="false"
:domain-line="false"
:grid-line="false"
:tick-format="(d: number) => {
const date = new Date(d)
return date.toLocaleDateString('en-US', {
month: 'short',
})
}"
:tick-values="chartData.map(d => d.date)"
/>
<VisAxis
type="y"
:tick-format="(d: number) => ''"
:tick-line="false"
:domain-line="false"
:grid-line="true"
/>
<ChartTooltip />
<ChartCrosshair
:template="componentToString(chartConfig, ChartTooltipContent, {
labelFormatter(d) {
return new Date(d).toLocaleDateString('en-US', {
month: 'long',
})
},
})"
:color="[chartConfig.desktop.color, chartConfig.mobile.color]"
/>
</VisXYContainer>
<ChartLegendContent />
</ChartContainer>
</template>Done. You've built your first chart! What's next?
Chart Config
The chart config is where you define the labels, icons and colors for a chart.
It is intentionally decoupled from chart data.
This allows you to share config and color tokens between charts. It can also works independently for cases where your data or color tokens live remotely or in a different format.
<script setup lang="ts">
import { Monitor } from "lucide-vue-next"
import type { ChartConfig } from "@/components/ui/chart"
const chartConfig = {
desktop: {
label: "Desktop",
icon: Monitor,
// A color like 'hsl(220, 98%, 61%)' or 'var(--color-name)'
color: "var(--chart-1)",
// OR a theme object with 'light' and 'dark' keys
theme: {
light: "var(--chart-1)",
dark: "var(--chart-2)",
},
},
} satisfies ChartConfig
</script>Theming
Charts has built-in support for theming. You can use css variables (recommended) or color values in any color format, such as hex, hsl or oklch.
CSS Variables
Define your colors in your css file
@layer base {
:root {
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
}
.dark {
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
}
}Add the color to your chartConfig
const chartConfig = {
desktop: {
label: "Desktop",
color: "var(--chart-1)",
},
mobile: {
label: "Mobile",
color: "var(--chart-2)",
},
} satisfies ChartConfighex, hsl or oklch
You can also define your colors directly in the chart config. Use the color format you prefer.
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
} satisfies ChartConfigUsing Colors
To use the theme colors in your chart, reference the colors using the format var(--color-KEY).
Components
<VisGroupedBar
:x="(d) => d.month"
:y="(d) => d.desktop"
color="var(--color-desktop)"
/>Chart Data
const chartData = [
{ browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]Tooltip
A chart tooltip contains a label, name, indicator and value. You can use a combination of these to customize your tooltip.
You can turn on/off any of these using the hideLabel, hideIndicator props and customize the indicator style using the indicator prop.
Use labelKey and nameKey to use a custom key for the tooltip label and name.
Chart comes with the ChartTooltip and ChartTooltipContent components. You can use these two components to add custom tooltips to your chart.
import { ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"<template>
<ChartTooltip />
<ChartCrosshair
:template="componentToString(chartConfig, ChartTooltipContent)"
/>
</template>Props
Use the following props to customize the tooltip.
| Prop | Type | Description |
|---|---|---|
labelKey | string | The config or data key to use for the label. |
nameKey | string | The config or data key to use for the name. |
indicator | dot line or dashed | The indicator style for the tooltip. |
hideLabel | boolean | Whether to hide the label. |
hideIndicator | boolean | Whether to hide the indicator. |
Colors
Colors are automatically referenced from the chart config.
Custom
To use a custom key for tooltip label and names, use the labelKey and nameKey props.
const chartData = [
{ browser: "chrome", visitors: 187, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]
const chartConfig = {
visitors: {
label: "Total Visitors",
},
chrome: {
label: "Chrome",
color: "var(--chart-1)",
},
safari: {
label: "Safari",
color: "var(--chart-2)",
},
} satisfies ChartConfig<template>
<ChartCrosshair
:template="componentToString(chartConfig, ChartTooltipContent, {
labelKey: 'visitors',
nameKey: 'browser'
})"
/>
</template>This will use Total Visitors for label and Chrome and Safari for the tooltip names.
Legend
You can use the custom <ChartLegendContent> components to add a legend to your chart.
import { ChartLegendContent } from "@/components/ui/chart"<template>
<ChartLegendContent />
</template>Colors
Colors are automatically referenced from the chart config.
Custom
To use a custom key for legend names, use the nameKey prop.
const chartData = [
{ browser: "chrome", visitors: 187, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]
const chartConfig = {
chrome: {
label: "Chrome",
color: "hsl(var(--chart-1))",
},
safari: {
label: "Safari",
color: "hsl(var(--chart-2))",
},
} satisfies ChartConfig<template>
<ChartLegendContent nameKey="browser" />
</template>This will use Chrome and Safari for the legend names.