Chart
NewAnatomy
Section titled “Anatomy”<Chart> <DonutChart /> <Legend> <LegendItem /> <LegendItem /> </Legend></Chart>Chart: Wraps and provides shared context (colors, currently hovered item, etc.) to child components. Not required if using a display-only chart without user interactions.DonutChart: Displays data as parts of a whole, with an optional center value and label. Currently the only chart type available in Stylus.Legend: Displays a list of labels and values related to the chart.
import { Chart, DonutChart, Legend, LegendItem } from "stylus-ui/Chart";
const data = [ { name: "Notion", amount: 281 }, { name: "VS Code", amount: 142 }, { name: "Slack", amount: 50 },];
export default () => ( <Chart className="flex items-center gap-8" data={data} category="name"> <DonutChart value="amount" /> <Legend className="w-48"> {data.map((item) => ( <LegendItem key={item.name} dataKey={item.name} label={item.name} value={item.amount} /> ))} </Legend> </Chart>);Donut chart
Section titled “Donut chart”For the simplest display, you can use DonutChart standalone, without the Chart wrapper.
import { DonutChart } from "stylus-ui/Chart";
const data = [ { name: "Notion", amount: 281 }, { name: "VS Code", amount: 142 }, { name: "Slack", amount: 50 },];
export default () => ( <DonutChart category="name" value="amount" data={data} className="size-16" />);Colors
Section titled “Colors”Each segment will automatically take on a color from the default palette. The available colors are brand, blue, green, teal, yellow, pink, fuchsia, purple, red, cyan, orange, and slate.
Specific colors only
Section titled “Specific colors only”By default, the chart cycles through all available colors in order. To use a specific subset of colors, pass an array of names to the colors prop:
import { DonutChart } from "stylus-ui/Chart";
const data = [ { name: "Primary", value: 40 }, { name: "Secondary", value: 30 }, { name: "Tertiary", value: 20 }, { name: "Other", value: 10 },];
export default () => ( <DonutChart category="name" value="value" data={data} colors={["brand", "pink", "cyan", "slate"]} />);Display value
Section titled “Display value”Display a sum of all chart segments in the center by setting showValue to true.
import { DonutChart } from "stylus-ui/Chart";import { formatIntlNumber } from "scribe-web-shared/functions";
const data = [ { name: "Notion", amount: 2814 }, { name: "VS Code", amount: 142 }, { name: "Slack", amount: 503 },];
export default () => ( <DonutChart category="name" value="amount" data={data} showValue />);Long values will automaically shrink to fit.
import { DonutChart } from "stylus-ui/Chart";import { formatIntlNumber } from "scribe-web-shared/functions";
const data = [ { name: "Notion", revenue: 4500600 }, { name: "VS Code", revenue: 3200800 }, { name: "Slack", revenue: 1800900 },];
export default () => ( <DonutChart category="name" value="revenue" data={data} showValue />);Formatting values
Section titled “Formatting values”Use the valueFormatter prop to format the display value. For example, you can use the formatIntlNumber helper to display locale-appropriate thousands separators for long numbers.
import { DonutChart } from "stylus-ui/Chart";import { formatIntlNumber } from "scribe-web-shared/functions";
const data = [ { name: "Notion", amount: 2814 }, { name: "VS Code", amount: 142 }, { name: "Slack", amount: 503 },];
export default () => ( <DonutChart category="name" value="amount" data={data} showValue valueFormatter={(v) => formatIntlNumber(v)} />);With label
Section titled “With label”To display text above the value, set label.
import { DonutChart } from "stylus-ui/Chart";import { formatIntlNumber } from "scribe-web-shared/functions";
const data = [ { name: "Notion", hours: 281 }, { name: "VS Code", hours: 142 }, { name: "Slack", hours: 50 },];
export default () => ( <DonutChart category="name" value="hours" data={data} showValue valueFormatter={(v) => `${formatIntlNumber(v)} hrs`} label="Yearly average" />);No data
Section titled “No data”When there’s no data or all values are zero, the chart displays a full ring with a - in the center:
import { DonutChart } from "stylus-ui/Chart";
export default () => ( <DonutChart category="name" value="amount" data={[]} showValue label="Yearly average" />);With legend
Section titled “With legend”Combine the DonutChart with the Legend component for interactive data visualization. The Chart wrapper automatically synchronizes hover and click states between components with zero boilerplate:
import React from "react";import { Chart, DonutChart, Legend, LegendItem } from "stylus-ui/Chart";
const data = [ { name: "Notion", amount: 281 }, { name: "VS Code", amount: 142 }, { name: "GitHub", amount: 87 }, { name: "Slack", amount: 50 }, { name: "Figma", amount: 43 },];
export default () => { const total = data.reduce((sum, item) => sum + item.amount, 0);
return ( <Chart className="flex items-center gap-8" data={data} category="name"> <DonutChart value="amount" label="Yearly average" valueFormatter={(v) => `${v} hrs`} showValue /> <Legend> {data.map((item) => ( <LegendItem key={item.name} dataKey={item.name} label={item.name} value={`${item.amount} hrs (${((item.amount / total) * 100).toFixed(1)}%)`} /> ))} </Legend> </Chart> );};With click interactions
Section titled “With click interactions”Add click handling to toggle selection by providing an onClick callback to the Chart component:
import React from "react";import { Chart, DonutChart, Legend, LegendItem } from "stylus-ui/Chart";
const data = [ { name: "Notion", amount: 281 }, { name: "VS Code", amount: 142 }, { name: "GitHub", amount: 87 }, { name: "Slack", amount: 50 }, { name: "Figma", amount: 43 },];
export default () => { const [selected, setSelected] = React.useState(null); const total = data.reduce((sum, item) => sum + item.amount, 0);
return ( <Chart className="flex items-center gap-8" data={data} category="name" selectedDataKey={selected} onClick={setSelected} > <DonutChart value="amount" label="Yearly average" valueFormatter={(v) => `${v} hrs`} showValue /> <Legend> {data.map((item) => ( <LegendItem key={item.name} dataKey={item.name} label={item.name} value={`${item.amount} hrs (${((item.amount / total) * 100).toFixed(1)}%)`} /> ))} </Legend> </Chart> );};With icons and logos
Section titled “With icons and logos”Each legend item accepts an icon prop for FontAwesome icons or a logo prop (with name and src) to display a favicon.
import React from "react";import { Chart, DonutChart, Legend, LegendItem } from "stylus-ui/Chart";import { getFavicon } from "stylus-ui/utils/getFavicon";import { faGrid2 } from "@fortawesome/pro-regular-svg-icons";
const data = [ { name: "Notion", url: "https://notion.so", amount: 281 }, { name: "Slack", url: "https://slack.com", amount: 142 }, { name: "Figma", url: "https://figma.com", amount: 87 }, { name: "Others", amount: 50 },];
export default () => { const total = data.reduce((sum, item) => sum + item.amount, 0);
return ( <Chart className="flex items-center gap-8" data={data} category="name" colors={["brand", "pink", "cyan", "slate"]} > <DonutChart value="amount" label="Yearly average" valueFormatter={(v) => `${v} hrs`} showValue /> <Legend> {data.map((item) => { const logoObj = item.url && { name: item.name, src: getFavicon({ url: item.url }), };
return ( <LegendItem key={item.name} dataKey={item.name} logo={logoObj} icon={!item.url ? faGrid2 : undefined} label={item.name} value={`${((item.amount / total) * 100).toFixed(1)}%`} /> ); })} </Legend> </Chart> );};