Skip to content

SketchyChart ​

A Neo-Brutalist chart rendered with Vue and SVG, using fractal noise and hatch textures for a hand-drawn appearance. The table disclosure uses Reka UI and the library's semantic table components.

Demo ​

Preview

Monthly net change

Unit: CNY 10,000; zero is the baseline. · Sketchy Line Chart · 6 data items

Monthly net change-1511.2537.563.7590JanuaryFebruaryMarchAprilMayJune

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

January · 30 · Item 1 of 6

Net order change by region

Unit: orders; positive and negative values lie on opposite sides of zero. · Sketchy Bar Chart · 4 data items

Net order change by region-12-4.5310.518NorthSouthEastWest

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

North · 18 · Item 1 of 4

Device visit share

Unit: visits; shares use every category. · Sketchy Pie Chart · 4 data items

Device visit share

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

Desktop · 45 · 45% · Item 1 of 4

  • Desktop45 (45%)
  • Mobile35 (35%)
  • Tablet15 (15%)
  • Other5 (5%)

The line and bar examples contain positive, negative, and zero values. Hover the graphic to read a value, or Tab to the data-item slider and use arrow keys. Expand the table to inspect the original values.

Installation ​

pnpm dlx brutx-vue@latest add sketchy-chart

Manual Copy Scope ​

The dependency command in the manual installation panel covers the external packages required by the chart source closure: reka-ui, class-variance-authority, clsx, tailwind-merge, and @lucide/vue. Configure Vue, Tailwind CSS, src/lib/utils.ts, and the design tokens through the base steps in the general manual installation guide. utils.ts is the shared class-name helper for local components and does not belong to the chart directory.

The chart's registry closure also includes button, slider, tooltip, table, and locale-zh-cn. When copying the source, preserve the directory layout and copy all of the following:

  • SketchyChart.vue, sketchy-chart-data.ts, sketchy-chart-variants.ts, useChartInteraction.ts, and index.ts from src/components/ui/sketchy-chart/;
  • the component directories and their variant and entry files from src/components/ui/button/, src/components/ui/slider/, src/components/ui/tooltip/, and src/components/ui/table/;
  • src/composables/useLocale.ts, useGlitchEffect.ts, and useReducedMotion.ts;
  • src/locales/en.ts, index.ts, types.ts, and zh-CN.ts;
  • src/lib/defaults.ts, z-index.ts, icon-size-variants.ts, env.ts, brutal-interaction-variants.ts, floating-content-variants.ts, and floating-animation-classes.ts.

These files cover the chart source, its registry component dependencies, and their internal helpers. Tests and screenshots are not needed. After copying, use the local import generated by the last step in the installation panel:

ts
import SketchyChart from '@/components/ui/sketchy-chart/SketchyChart.vue'

Keep the relative imports in the copied source and make sure the @/ alias resolves. This import is for the copied local source; the brutx-ui-vue import in the usage example is for the published package.

Usage ​

vue
<script setup>
import { SketchyChart } from 'brutx-ui-vue'

const data = [
    { label: 'Jan', value: 30 },
    { label: 'Feb', value: 65 },
    { label: 'Mar', value: 45 },
]
</script>

<template>
    <SketchyChart title="Monthly sales" description="Unit: USD" type="line" :data="data" />
</template>

Variants ​

VariantDescription
lineLine chart with shadow fill area and node circles
barBar chart with hatch pattern fill and hard shadows
piePie chart using design token color palette and thick black borders
vue
<template>
    <SketchyChart type="bar" :data="data" />
</template>

Sketchy Jitter ​

The sketchiness prop controls the hand-drawn jitter amplitude. Higher values produce more pronounced wobble. Use 0-10 as a practical range; the component does not clamp the supplied value:

vue
<SketchyChart type="line" :data="data" :sketchiness="8" />

Data Handling ​

  • Lines and bars: Accept finite positive, negative, and zero values. The domain includes zero and the actual extrema; bars and line areas use a zero baseline.
  • Pie charts: Accept finite nonnegative values and calculate proportions from the complete dataset. Zero values remain in the legend, slider, and table without creating slices. Tiny proportions that cannot form a drawable slice also retain their original readings. Pointer hits follow the slices actually drawn.
  • Invalid values: Any NaN, infinity, or negative pie value invalidates the entire graphic. The table identifies invalid cells while preserving every label.
  • Empty and zero data: Empty arrays show an empty state. All-zero lines and bars still render zero values. All-zero pies show a zero-total state with unavailable percentages.
  • Complete categories: Datasets above 30 items retain all data and endpoints; only visible category ticks are thinned. Use the complete table for dense data.
  • Formatting: valueFormatter consistently formats ticks, legends, and table values, receives only valid finite numbers, and should be deterministic and side-effect-free. Percentages use locale formatting independently; rounded values may not total 100%.

Data Semantics Migration ​

Negative values now retain their sign, and negative pie values invalidate the chart. Datasets above 30 items are rendered in full. If your application needs absolute values, aggregation, or sampling, explicitly transform the input and explain that transformation. Use title to distinguish charts and description for units, methodology, and important trends.

Complete Categories and Static Readings ​

The following example retains all 31 daily items. Focus the slider and press End to read day 31, then Home to return to the first item. Expand the table to inspect all 31 rows. Fewer visible ticks do not reduce the dataset.

Preview

Net change over 31 days

Unit: transactions; positive, negative, and zero daily changes are retained. · Sketchy Bar Chart · 31 data items

Net change over 31 days-8-241016Day 1Day 6Day 11Day 16Day 21Day 26Day 31

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

Day 1 · 12 · Item 1 of 31

Toggle “Static chart” to set interactive=false, removing graphic tooltips and the item slider while keeping the table disclosure. Static mode suits overview displays where details are read through the table.

vue
<SketchyChart title="Net change over 31 days" type="bar" :data="data" :interactive="false" />

Data State Examples ​

Switch between a single item, an empty array, all-zero data, an invalid number, a negative pie value, and a tiny proportion. Compare the graphic state, reading entry, and table. A single item uses a read-only focus entry; empty and invalid datasets explain their state. All-zero pies have unavailable percentages.

Preview

Pie data states

Switch inputs to compare the graphic, focus entry, and complete table. · Sketchy Pie Chart · 1 data items

Pie data states

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

Category A · 12 · 100% · Item 1 of 1
  • Category A12 (100%)

“Tiny proportion” uses 1e-15 and Number.MAX_VALUE, displayed in scientific notation. The tiny item occupies no drawable slice, but its original value remains readable through the legend, slider, and table. A displayed 0% reflects percentage rounding, not a zero input value.

Reading Interaction ​

Hover the nearest horizontal line position, a bar category area, or a pie slice to read an item. The pie legend also exposes zero values. Move into the tooltip to keep it open. Escape dismisses it and small movements within the same item keep it closed. Touch selects an item; tapping it again or tapping outside dismisses it. Swiping preserves page scrolling.

The visible data-item slider includes every category in input order. Arrow keys move between items, Home/End reach the endpoints, and Tab leaves normally. Single, empty, and invalid datasets use a read-only focus region. Pointer activity is independent of the slider position. Array replacement, insertion, deletion, reordering, label/value edits, or chart-type changes clear the tooltip and reset the explorer. Scrolling and resizing preserve the active item; locale and formatter changes refresh its text.

Set :interactive="false" for a static chart with the complete table disclosure still available. Read dense data through the slider or table; visual distinguishability depends on available space.

Dynamic Data Updates ​

The following actions run 3 seconds after clicking, giving you time to focus the slider and press End to read the last item. An update dismisses the tooltip and returns the slider to the first item. Reordering keeps labels paired with their values. Type changes cycle through line, bar, and pie.

Preview

Schedule an update. Current type: Line chart

Dynamic category totals

Unit: transactions; exploration restarts at the first item after updates. · Sketchy Line Chart · 3 data items

Dynamic category totals06121824Category ACategory BCategory C

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

Category A · 12 · Item 1 of 3

In your application, update the reactive input directly; the delay is for demonstration. Reset cancels any pending action and restores the original data.

Consistent Formatting Example ​

Amounts use Intl.NumberFormat to display Chinese yuan. Compare the axis ticks, tooltip, legend, and table: they share the same valueFormatter. Pie shares are still calculated from the original amounts and formatted separately.

Preview

Monthly net income

Unit: CNY · Sketchy Bar Chart · 3 data items

Monthly net income-CN¥1,200.00-CN¥99.87CN¥1,000.25CN¥2,100.38CN¥3,200.50JanuaryFebruaryMarch

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

January · -CN¥1,200.00 · Item 1 of 3

Donation allocation

Unit: CNY; shares are calculated from the original amounts. · Sketchy Pie Chart · 3 data items

Donation allocation

Browse data items

Use arrow keys to read items, Home and End to reach the first and last, Tab to leave, and Escape to dismiss the tooltip.

Education · CN¥1,200.00 · 66.7% · Item 1 of 3

  • EducationCN¥1,200.00 (66.7%)
  • EnvironmentCN¥600.00 (33.3%)
  • OtherCN¥0.00 (0%)
ts
const currency: Intl.NumberFormat = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'CNY',
})
function formatCurrency(value: number): string {
    return currency.format(value)
}
vue
<SketchyChart title="Monthly net income" type="bar" :data="data" :value-formatter="formatCurrency" />

Tooltip Slot ​

vue
<SketchyChart title="Device share" type="pie" :data="data">
    <template #tooltip="{ label, formattedValue, formattedPercentage }">
        {{ label }}: {{ formattedValue }} ({{ formattedPercentage }})
    </template>
</SketchyChart>

The slot exposes index, label, raw value, formattedValue, and pie-specific percentage (0 to 1) and formattedPercentage. Both percentage fields are undefined for other chart types or unavailable proportions. Use display content only; links, buttons, and inputs belong in a separate interactive overlay. The slider and table provide equivalent readings.

API Reference ​

SketchyChart — Props
NameTypeDefaultDescription
type
ChartType | undefined
"line"
Selects a sketchy line, bar, or pie chart.
Details

Declared type

ChartType | undefined

Literal values

  • "bar"
  • "line"
  • "pie"

Referenced types

ChartType
Type definition — ChartType
export type ChartType = 'line' | 'bar' | 'pie'

Default value details

Resolved value
"line"

Source

SketchyChart.vue:26

packages/ui/src/components/sketchy-chart/SketchyChart.vue

data
ChartDataItem[] | undefined
[]

Factory evaluated per instance

Array of chart items, each with a label and value. Line and bar charts support positive, negative, and zero values; pie charts support non-negative values.
Details

Declared type

ChartDataItem[] | undefined

Referenced types

ChartDataItem
Type definition — ChartDataItem
export interface ChartDataItem {
    label: string
    value: number
}

Default value details

Resolved value
[]

Source

SketchyChart.vue:27

packages/ui/src/components/sketchy-chart/SketchyChart.vue

title
string | undefined
undefined
Business title of the chart, associated with graphic accessibility name and table caption.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

SketchyChart.vue:28

packages/ui/src/components/sketchy-chart/SketchyChart.vue

description
string | undefined
undefined
Units, statistical methodology, and important trend description.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

SketchyChart.vue:29

packages/ui/src/components/sketchy-chart/SketchyChart.vue

valueFormatter
((value: number) => string) | undefined
undefined
Numeric formatting function that standardizes scales, legends, and table values.
Details

Declared type

((value: number) => string) | undefined

Default value details

Resolved value
undefined

Source

SketchyChart.vue:30

packages/ui/src/components/sketchy-chart/SketchyChart.vue

interactive
boolean | undefined
true
Enables interactive tooltips and the data-item slider.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
true

Source

SketchyChart.vue:31

packages/ui/src/components/sketchy-chart/SketchyChart.vue

sketchiness
number | undefined
2
Controls the SVG hand-drawn filter intensity. The value scales an internal base frequency; the source does not clamp the supplied number to a range.
Details

Declared type

number | undefined

Default value details

Declaration
DEFAULT_SKETCHINESS

Source: packages/ui/src/components/sketchy-chart/SketchyChart.vue

Resolved value
2

Source

SketchyChart.vue:32

packages/ui/src/components/sketchy-chart/SketchyChart.vue

grid
boolean | undefined
true
Shows the background grid for line and bar charts. Pie charts do not render a grid.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
true

Source

SketchyChart.vue:33

packages/ui/src/components/sketchy-chart/SketchyChart.vue

width
number | undefined
600
Sets the width used by the SVG viewBox and chart calculations, in SVG user units.
Details

Declared type

number | undefined

Default value details

Declaration
SKETCHY_CHART_DEFAULT_WIDTH_PX

Source: packages/ui/src/components/sketchy-chart/SketchyChart.vue

Resolved value
600

Source

SketchyChart.vue:34

packages/ui/src/components/sketchy-chart/SketchyChart.vue

height
number | undefined
400
Sets the height used by the SVG viewBox and chart calculations, in SVG user units.
Details

Declared type

number | undefined

Default value details

Declaration
SKETCHY_CHART_DEFAULT_HEIGHT_PX

Source: packages/ui/src/components/sketchy-chart/SketchyChart.vue

Resolved value
400

Source

SketchyChart.vue:35

packages/ui/src/components/sketchy-chart/SketchyChart.vue

class
string | undefined
undefined
Custom CSS classes appended to the outer chart container.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

SketchyChart.vue:36

packages/ui/src/components/sketchy-chart/SketchyChart.vue

SketchyChart — Slots
NameSignature or typeDescription
#tooltip
TooltipReading
Custom content for the chart reading tooltip.
Details

Declared type

TooltipReading

Referenced types

TooltipReading
Type definition — TooltipReading
interface TooltipReading {
    index: number
    label: string
    value: number
    formattedValue: string
    percentage: number | undefined
    formattedPercentage: string | undefined
}

Source

SketchyChart.vue:53

packages/ui/src/components/sketchy-chart/SketchyChart.vue

Accessibility ​

  • Graphic semantics: SVG uses role="img" and instance-unique IDs to associate its visible title, description, and data state.
  • Keyboard readings: The slider has one focusable thumb. Its aria-valuetext includes category, formatted value, position, count, and pie percentage. The visual tooltip does not repeat announcements. Inside a dialog, the first Escape dismisses the tooltip and the next closes the dialog.
  • Equivalent readings: A keyboard-operable data-table disclosure retains focus on its button. The complete semantic table includes a caption, column headers, and percentages for pie charts.
  • Context: Supply meaningful titles and necessary trend descriptions to distinguish charts and convey their purpose.

Brute force builds.