1 GitHub star = 1 new component.

Star the repo
Charts & Statschartsvgzero-dependencybarhorizontalrankingtop-list

Horizontal Bar Chart

Ranked horizontal bars with labels and values, single color and optional highlight of one item.

Live Preview

Top pages

Unique visitors, last 30 days

  1. /pricing18.4k
  2. /docs/getting-started15.2k
  3. /13k
  4. /blog/astro-59.3k
  5. /components7.1k
  6. /changelog4.3k
View data
ItemValue
/pricing18.4k
/docs/getting-started15.2k
/13k
/blog/astro-59.3k
/components7.1k
/changelog4.3k

Usage

Copy and paste this code into your React component:

tsx
import { HorizontalBarChart } from 'react-component-kit-ui/charts';

<HorizontalBarChart items={[
    { label: '/pricing', value: 18420 },
    { label: '/docs', value: 15210 },
    { label: '/', value: 12980 },
  ]} highlight="/pricing" />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/HorizontalBarChart.tsx + HorizontalBarChart.css:

HorizontalBarChart.tsx
'use client';

import type { CSSProperties } from 'react';
import ChartFrame from './ChartFrame';
import { formatValue } from './chart-utils';
import './HorizontalBarChart.css';

/** "a: b; --c: d" โ†’ style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

/**
 * HorizontalBarChart โ€” Ranked horizontal bars with labels on the left and values
 * on the right. One series โ†’ one color; optionally highlight a single bar.
 *
 * @param {Array<{label: string, value: number}>} items - Bars to draw.
 * @param {boolean} sort - Sort descending by value.
 * @param {string} highlight - Label to emphasise; other bars recede.
 * @param {string} prefix - Value prefix.
 * @param {string} suffix - Value suffix.
 * @param {string} color - Bar color.
 * @param {string} variant - Card style (glass|solid|ghost).
 * @param {string} size - Density (sm|md|lg).
 */
export interface HorizontalBarChartProps {
  title?: string;
  subtitle?: string;
  items?: Array<{ label: string; value: number }>;
  sort?: boolean;
  highlight?: string;
  prefix?: string;
  suffix?: string;
  color?: string;
  variant?: 'glass' | 'solid' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

export function HorizontalBarChart({
  title = 'Top pages',
  subtitle = 'Unique visitors, last 30 days',
  items = [
    { label: '/pricing', value: 18420 },
    { label: '/docs/getting-started', value: 15210 },
    { label: '/', value: 12980 },
    { label: '/blog/astro-5', value: 9340 },
    { label: '/components', value: 7120 },
    { label: '/changelog', value: 4310 },
  ],
  sort = true,
  highlight,
  prefix = '',
  suffix = '',
  color = 'var(--chart-1, #3987e5)',
  variant = 'glass',
  size = 'md',
  className = '',
}: HorizontalBarChartProps) {
  const rows = sort ? [...items].sort((a, b) => b.value - a.value) : items;
  const max = Math.max(...rows.map((r) => r.value)) || 1;
  const fmt = (v: number) => formatValue(v, prefix, suffix);
  return (
    <>
      <ChartFrame title={title} subtitle={subtitle} variant={variant} size={size} className={className} table={{ headers: ['Item', 'Value'], rows: rows.map((r) => [r.label, fmt(r.value)]) }}>
        <ol className="hb" aria-label={title} data-rk-344822="">
          {rows.map((r, i) => {
            const dim = highlight && highlight !== r.label;
            return (
              <li className="hb__row cf-mark" tabIndex={0} style={st(`--hb-w:${(r.value / max) * 100}%; --hb-c:${color}; --hb-o:${dim ? 0.35 : 1}; --hb-i:${i}`)} data-tip-title={r.label} data-tip={`${color}::${fmt(r.value)} ยท ${((r.value / max) * 100).toFixed(0)}% of top`} aria-label={`${i + 1}. ${r.label}: ${fmt(r.value)}`} data-rk-344822="">
                <span className="hb__label" data-rk-344822="">{r.label}</span>
                <span className="hb__track" aria-hidden="true" data-rk-344822=""><span className="hb__bar" data-rk-344822=""></span></span>
                <span className="hb__value" data-rk-344822="">{fmt(r.value)}</span>
              </li>
            );
          })}
        </ol>
      </ChartFrame>
    </>
  );
}

export default HorizontalBarChart;
HorizontalBarChart.css
/* HorizontalBarChart โ€” ported from astro-component-kit (charts/HorizontalBarChart.astro) */

.hb:where([data-rk-344822]) {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}
.hb__row:where([data-rk-344822]) {
  display: grid;
  grid-template-columns: minmax(6rem, 34%) 1fr auto;
  align-items: center;
  gap: 0.75rem;
  min-height: 32px;
  padding: 0.15rem 0.35rem;
  border-radius: 8px;
  cursor: default;
}
.hb__row:hover:where([data-rk-344822]),
.hb__row:focus-visible:where([data-rk-344822]) {
  background: rgb(var(--ink-rgb, 255 255 255) / 0.04);
}
.hb__row:focus-visible:where([data-rk-344822]) {
  outline: 2px solid var(--c-primary-light, #d4a017);
  outline-offset: 1px;
}
.hb__label:where([data-rk-344822]) {
  font-size: 0.8125rem;
  color: var(--c-text-2, #a3a3a3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hb__track:where([data-rk-344822]) {
  height: 10px;
  border-radius: 4px;
  background: rgb(var(--ink-rgb, 255 255 255) / 0.04);
  overflow: hidden;
}
.hb__bar:where([data-rk-344822]) {
  display: block;
  height: 100%;
  width: var(--hb-w);
  border-radius: 0 4px 4px 0;
  background: var(--hb-c);
  opacity: var(--hb-o);
  transform-origin: left;
  animation: horizontal-bar-chart-hb-grow 0.7s cubic-bezier(0.4, 0, 0.2, 1) both;
  animation-delay: calc(var(--hb-i) * 60ms);
}
.hb__value:where([data-rk-344822]) {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--c-text-1, #fff);
  font-variant-numeric: tabular-nums;
  min-width: 3.5rem;
  text-align: right;
}
@keyframes horizontal-bar-chart-hb-grow {
  from { transform: scaleX(0); }
}
@media (max-width: 480px) {
  .hb__row:where([data-rk-344822]) { grid-template-columns: 1fr auto; }
  .hb__track:where([data-rk-344822]) { grid-column: 1 / -1; grid-row: 2; }
}
@media (prefers-reduced-motion: reduce) {
  .hb__bar:where([data-rk-344822]) { animation: none; }
}

Quick Info

Category
Charts & Stats
Filename
HorizontalBarChart.tsx
Dependencies
None โ€” pure React + CSS
Tags
chartsvgzero-dependencybarhorizontalrankingtop-list