Column Chart
Вертикальные столбцы для упорядоченных категорий – временных интервалов или рейтингов. Дисциплина data-ink (Тафти): один акцент, без сетки, моноширинные цифры, прямые подписи значений по умолчанию, встроенная строка источника и доступные состояния пустоты / загрузки / ошибки.
Studio · Код, график, настройки
Трёхпанельный верстак. Меняйте любую настройку справа – график в центре обновляется вживую, а код слева перегенерируется, готовый к вставке в ваш проект.
import { ColumnChart } from "@/components/charts/column-chart";
const data = [142, 168, 187, 159, 203, 178, 215];
const labels = ["ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ", "ВС"];
export function Example() {
return (
<ColumnChart
data={data}
labels={labels}
height={240}
gap={4}
header={{ title: "Активные пользователи", subtitle: "Последние 7 дней" }}
trend={0.184}
source="Brock Analytics, 2026"
onBarClick={(point, index) => {
console.log("clicked", index, point);
}}
onBarHover={(point, index) => {
// point is null on mouse leave
setHoverIndex(index);
}}
onBarFocus={(point, index) => {
// Fires on keyboard navigation
announce(`Bar ${index + 1}: ${point.value}`);
}}
exportable
exportFileName="active-users-7d"
/>
);
}| Label | Value |
|---|---|
| ПН | 142 |
| ВТ | 168 |
| СР | 187 |
| ЧТ | 159 |
| ПТ | 203 |
| СБ | 178 |
| ВС | 215 |
Установка
npx shadcn@latest add https://brockui.com/r/column-chartИспользование
import { ColumnChart } from "@/components/charts/column-chart";
const data = [142, 168, 187, 159, 203, 178, 215];
const labels = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
export function Example() {
return (
<ColumnChart
data={data}
labels={labels}
height={220}
trend={0.184}
source="Brock Analytics, 2026"
/>
);
}
// Opinionated defaults — but every sub-component is yours to replace via the
// `slots` prop. The data is passed in; you control the rendering.
export function WithCustomTooltip() {
return (
<ColumnChart
data={data}
labels={labels}
slots={{
tooltip: ({ label, value }) => (
<div className="border-2 border-brock-accent p-2">
<span className="font-mono tabular-nums">{value}</span> · {label}
</div>
),
}}
/>
);
}Пропы
| Имя | Тип | По умолчанию | Описание |
|---|---|---|---|
| data | number[] | DataPoint[] | — | Значения столбцов. Две формы: number[] (с пропом labels) или { key?, label?, value, meta?, pattern?, color?, highlight?, note? }[] (объектная форма). key – стабильный адрес для аннотаций и focusBar (по умолчанию label); meta – ваши данные, возвращаются нетронутыми в каждом коллбэке; отрицательные значения рендерятся ниже нулевой базы. Синтетический столбец «Other» несёт isOther + items[] (только на выходе) |
| sort | 'none' | 'asc' | 'desc' | 'none' | Сортировка столбцов по значению (стабильная). 'none' сохраняет исходный порядок – честный дефолт для временных интервалов; asc/desc превращает график в рейтинг |
| topN | number | { n, label?, pinned?, distinct? } | undefined | Оставить N крупнейших столбцов, свернув хвост в один агрегат «Other» (сумма). По умолчанию: закреплён последним независимо от sort, приглушённая заливка --brock-other. Коллбэки получают isOther + свёрнутые items[]. Число = все дефолты |
| labels | string[] | undefined | Подписи оси X (Hack mono под столбцами + в тултипе). Используются только при data: number[] |
| height | number | 200 | Высота графика в пикселях (ось Y + область столбцов) |
| gap | number | 4 | Зазор между столбцами в пикселях. Сужается автоматически на плотных данных (60+ столбцов) |
| accent | string | var(--brock-accent) | Переопределение цвета заливки (любой CSS-цвет или var). По умолчанию – оранжевый Brock |
| barRadius | number | 0 | Радиус верхних углов в px. Типичные значения: 0 (острые), 2 (едва заметный), 6 (скруглённые) |
| header | { title?, subtitle? } | undefined | Блок заголовка и подзаголовка над графиком |
| xAxis | { title?, hideTicks? } | undefined | Настройка оси X (заголовок под подписями, скрытие подписей делений) |
| yAxis | { title?, max?, hideTicks? } | undefined | Настройка оси Y. min намеренно отсутствует – база столбчатого графика всегда ноль (обрезанные столбцы лгут). max только расширяет шкалу: значения ниже максимума данных игнорируются с предупреждением в dev |
| numberFormat | { prefix?, suffix?, decimals?, locale?, notation?, style?, currency? } | undefined | Форматирование чисел для оси Y, тултипа и подписей значений. Поддерживает локаль BCP-47, notation Intl.NumberFormat ('compact' → 1,2 тыс.), style ('currency' / 'percent') и валюту ISO 4217. Явные formatValue/yAxisFormat сильнее |
| dataLabels | { show?: boolean | 'auto', format? } | { show: 'auto' } | Прямые подписи значений у внешнего конца каждого столбца (Hack mono; у отрицательных – зеркально снизу). 'auto' (дефолт) показывает подписи И скрывает ось Y при ≤ 8 столбцах – ось избыточна, когда каждое значение напечатано. Явный yAxis.hideTicks сильнее. format(value, datum) переопределяет numberFormat |
| pattern | 'solid' | 'hatched' | 'solid' | Заливка всех столбцов по умолчанию. Per-bar pattern на точке данных сильнее. Штриховка кодирует «историческое/оценка/в работе» без второго цвета (Тафти) |
| hatchUntilIndex | number | undefined | Шорткат: столбцы с ИСХОДНЫМ индексом < N штрихуются (применяется до sort/topN – паттерн едет со своим датумом). Классическое «факт vs прогноз» |
| hatchFromIndex | number | undefined | Зеркало hatchUntilIndex: штрихуются столбцы с индексом >= N. Удобно для прогнозных хвостов. Совмещается с hatchUntilIndex (объединение) |
| patternStyle | 'diagonal' | 'diagonal-reverse' | 'dots' | 'vertical' | 'horizontal' | 'diagonal' | Вид штриховки (на уровне графика). Per-bar pattern решает, штрихуется ли столбец; этот проп – как выглядит штриховка. 'dots' – для печати и оттенков серого |
| scroll | 'none' | 'auto' | 'none' | Поведение при нехватке ширины. 'auto' включает горизонтальный скролл; ось Y прижата слева, столбцы и ось X скроллятся вместе |
| minBarWidth | number | 4 | Минимальная ширина столбца в px. Вместе со scroll='auto' задаёт min-width графика: N*minBarWidth + (N−1)*gap. При scroll='none' игнорируется |
| bands | { from, to, label?, color? }[] | undefined | Плот-бенды – подсвеченные вертикальные зоны по ЭКРАННЫМ позициям. Редакционный паттерн («Q3», «окно деплоя»). Рисуются за столбцами с низкой непрозрачностью; индексы ограничиваются диапазоном данных. Бенды предполагают исходный порядок – сочетание с sort даёт предупреждение в dev (зона «Q3» после пересортировки бессмысленна) |
| trend | number | undefined | Десятичный индикатор тренда: 0.184 → ↗ +18.4%. Оранжевый при росте, приглушённый при падении |
| referenceLine | { value: number | { stat: 'mean' | 'median' }, label? } | undefined | Пунктирная референсная линия – фиксированный порог («цель Q3») или статистика по ИСХОДНЫМ данным (sort/topN не должны двигать статистику). Статистики подписываются Mean/Median автоматически. Участвует в шкале с обеих сторон – отрицательные и нулевые (break-even) референсы остаются видимыми |
| source | string | undefined | Строка атрибуции под графиком (паттерн FT) |
| animation | { enabled?, duration? } | { enabled: true, duration: 400 } | Каскадный подъём столбцов при монтировании. Автоматически отключается при prefers-reduced-motion |
| loading | boolean | false | Состояние загрузки. Без данных → полный скелетон (сплошные столбцы-плейсхолдеры + доступная подпись загрузки, ARIA role=status). С данными → полупрозрачный оверлей со спиннером для фонового обновления. Уважает prefers-reduced-motion |
| error | Error | string | null | null | Терминальная ошибка. Замещает график даже при наличии данных (устаревшие данные рядом с ошибкой вводят в заблуждение). Принимает Error, строку или null. ARIA role=alert |
| onRetry | () => void | undefined | Коллбэк кнопки повтора в дефолтном состоянии ошибки. Кнопка рендерится только когда проп передан |
| loadingLabel | string | 'Loading…' | Доступная подпись состояния загрузки (скелетона), используется как его ARIA-метка. Переопределите для локализации |
| errorLabel | string | 'Error' | Подпись над сообщением об ошибке и ARIA-метка. Переопределите для локализации |
| retryLabel | string | 'Retry' | Надпись на кнопке повтора в дефолтном состоянии ошибки. Переопределите для локализации |
| loadingFallback | ReactNode | undefined | Полная замена дефолтного скелетона и оверлея. Для брендированного состояния загрузки |
| errorFallback | ReactNode | (error: Error) => ReactNode | undefined | Полная замена дефолтного UI ошибки. React-нода или функция, получающая нормализованный Error |
| exportable | boolean | { png?, svg?, csv?, copy? } | false | Показать тулбар экспорта (справа сверху). true – все 4 действия; объектная форма – выборочно. Императивные методы ref работают в любом случае |
| exportFileName | string | (format) => string | 'chart' | Базовое имя файла выгрузки. Строка – фиксированное, функция – по формату. Расширение (.png/.svg/.csv) добавляется автоматически |
| onExport | (format, artifact) => void | undefined | Срабатывает после завершения экспорта. Получает формат ('png'|'svg'|'csv'|'copy') и артефакт (Blob для png/copy, строка для svg/csv). Для аналитики и своих share-сценариев |
| ref | Ref<ColumnChartHandle> | — | Императивный API: { exportSVG, exportPNG, exportCSV, copyImage, focusBar, getSelection }. Экспорт работает даже в loading/error/empty. focusBar(target) принимает экранный индекс (с ограничением) ИЛИ стабильный key (неизвестный key → -1). getSelection() возвращает { index (экранный), key (стабильный), point } или null |
| onBarClick | (point, index, event) => void | undefined | Срабатывает на клик, тап или Enter/Space на сфокусированном столбце. Событие – MouseEvent или KeyboardEvent. При переданном пропе столбцы получают cursor-pointer |
| onBarHover | (point | null, index | null) => void | undefined | Срабатывает при наведении (point + index) и при уходе из области столбцов (null, null). Синхронизируйте свои легенды и панели деталей |
| onBarFocus | (point, index) => void | undefined | Срабатывает при смене клавиатурного фокуса между столбцами (стрелки, Home/End, Tab, программный focusBar()). Отслеживает позицию roving tabindex |
| slots | ColumnChartSlots | {} | Словарь headless-слотов. Каждый слот заменяет дефолтный саб-компонент: tooltip (per-bar), empty (нет данных), loading (скелетон), error (терминальная), toolbar (чипы экспорта), caption (под источником), watermark (оверлей фигуры). Каждый слот получает типизированные пропы. Слоты сильнее шорткатов loadingFallback / errorFallback |
| caption | string | undefined | Короткая редакционная подпись-примечание – курсив с левой границей, под строкой источника. Паттерн полей FT/писем Stripe. slots.caption сильнее |
| watermark | string | undefined | Диагональная вотермарка – едва заметный пиксельный текст (≈6% непрозрачности) поверх графика. Маркер жизненного цикла документа (DRAFT, CONFIDENTIAL) – не брендинг (для атрибуции есть source). Намеренно ПЕЧАТАЕТСЯ: бумажный конфиденциальный отчёт обязан нести маркировку. slots.watermark сильнее |
| annotations | ColumnChartAnnotation[] | undefined | Свободные редакционные аннотации в точке (x, y) пространства данных. x: число = ИСХОДНЫЙ индекс (едет со своим датумом сквозь sort/topN; если датум свернулся в «Other» – пропускается с предупреждением в dev) или строка = совпадение по key/label. y может быть отрицательным. { x, y, text, anchor?, arrow?, color? }; пунктирная стрелка опциональна. Воспроизводится в SVG/PNG-экспорте |
| chartType | string | 'column' | Машиночитаемый идентификатор, проставляется на фигуре как data-chart-type. Входит в toJSON(). AI/LLM-инструменты и аналитика используют его, чтобы понимать тип графика |
| dataDescription | string | undefined | Описание данных на естественном языке («Дневная аудитория, последние 7 дней»). Проставляется как data-description. Для AI-промптов и редакционной провенанс. Не путать с `description` (авто-метка для скринридера) |
| data-testid | string | undefined | QA-селектор, пробрасывается на фигуру. Стабилен при рефакторинге классов – конвенция Testing Library / Playwright |
| description | string | auto-generated | Доступное описание для скринридеров (figcaption + подпись таблицы). По умолчанию: 'Column chart with N data points. Source: ...' |
| formatValue | (value, datum?) => string | toLocaleString() | Свой форматтер значений для тултипов, подписей и sr-таблицы. Вторым аргументом получает датум (key, meta, isOther…) для контекстного форматирования. Сильнее numberFormat |
| yAxisFormat | (v: number) => string | toLocaleString | Функция форматирования подписей делений оси Y. Сильнее numberFormat |
Доступность
Построен по WCAG 2.2 AA. Клавиатурная навигация, поддержка скринридеров, уважает prefers-reduced-motion.
Честное ограничение: автогенерируемые ARIA-описания компонента («Column chart with 7 data points. Highest: …») – на английском. Если ваш продукт для русскоязычных пользователей, передайте собственный description и локализуйте loadingLabel/errorLabel/retryLabel – locale-pack компонента в планах.
| Tab | Фокус внутрь графика (одна точка останова) |
| ← → ↑ ↓ | Навигация между столбцами (roving tabindex) |
| Home | К первому столбцу |
| End | К последнему столбцу |
- ·
<figure role="figure">оборачивает график;aria-labelledbyуказывает на figcaption - · Каждый столбец –
role="graphics-symbol"сaria-label="LABEL: value" - · Скрытая
<table class="sr-only">даёт табличную сводку данных (подпись + строка на каждую точку) - · Индикатор тренда получает человекочитаемую метку («Trend up 18.4 percent») – стрелки скрыты от AT
Дизайн-ходы
- 1. Моноширинные числа оси Y + tabular-nums (шрифт Hack) – значения выравниваются по ширине цифры.
- 2. Один
--brock-accent(оранжевый) для всех столбцов – по обе стороны нуля. Без градиентов, свечения и палитр; per-barcolorзарезервирован под единичные редакционные исключения (аномалия, текущий период). - 3. Без сетки. Одна линия 1px на нулевой базе (data-ink, Тафти).
- 4. Тултип при наведении: подпись периода в Geist sans + значение в Hack mono, в единой приподнятой карточке.
- 5. Каскадная анимация появления (30 мс на столбец, scale-Y от базы). Отключается при
prefers-reduced-motion. - 6. Встроенный проп
sourceрендерит строку атрибуции в стиле FT/Bloomberg под графиком. - 7. Понятное пустое состояние (иконка + сообщение
No data) при пустом наборе; полная машина состояний черезloading/error(сплошной скелетон, оверлей обновления со спиннером, повтор) в том же визуальном языке.
Когда использовать
Column Chart подходит для упорядоченных категорий, где каждый столбец – дискретный интервал: временной (часы, дни, недели, вызовы агента в минуту) или ранжированный (трафик по каналам через sort + topN, выручка по регионам, прибыль/убыток по месяцам – отрицательные значения полноправны). Лучше всего показывает объём, количество и ритм активности с первого взгляда – разреженные оси не спорят с данными.
Когда не использовать
Для непрерывных трендов – Line Chart. Для крошечных графиков внутри метрик-карточек и текста – Sparkline. Для рейтингов с длинными подписями (горизонтальные полосы) – Bar Chart (скоро). Для состава во времени – Stacked Column Chart (скоро).
Источники
- · Financial Times Visual Journalism – разреженные оси, строка источника, одноцветные столбцы
- · Годовые письма Stripe – числа внутри редакционного текста
- · The Pudding – интерактивный сторителлинг со сдержанностью
- · Эдвард Тафти, The Visual Display of Quantitative Information – дисциплина data-ink