Nasaq

SegmentBar

Small charts that Recharts does not give you, a proportion bar with a legend of values, a progress ring, a centred funnel with step conversion and a table-row trend cell with a sparkline or mini bar.

PreviewOpen ↗

Code

import { ProgressRing, SegmentBar } from "@fadymondy/nasaq/web";export function Overview() {  return (    <div className="flex items-center gap-6">      <ProgressRing value={72} label="Onboarding" caption="of 25 steps" />      <SegmentBar        className="flex-1"        segments={[          { id: "organic", label: "Organic", value: 4200 },          { id: "paid", label: "Paid", value: 2100 },          { id: "referral", label: "Referral", value: 900 },        ]}      />    </div>  );}

Charts & Maps · beta

Live examples and controls: SegmentBar in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/chart-extras.json

Four small charts built next to ChartContainer. They are HTML and SVG, not Recharts, because they have no axes: a bar cut into shares, a ring, a funnel and a row cell. TrendCell reuses the existing Sparkline and MiniBar and adds the figure and its change beside them.

Every one of them carries its meaning in text as well as colour: the legend of SegmentBar lists each value and share, the ring prints its percentage, FunnelSteps writes the conversion between steps, and TrendCell shows an arrow and a signed figure.

When to use

  • SegmentBar: how a whole splits (channels, plan mix, ticket status, storage by type), or how much of a capacity is used.
  • ProgressRing: one completion or utilisation figure in a card, a list row or a table.
  • FunnelSteps: a short funnel with the conversion between steps in a card. Use FunnelChart for a segment comparison or a saved funnel list.
  • TrendCell: a table column that needs a figure, its change and a mini trend.

When not to use

Import

import { SegmentBar, ProgressRing, FunnelSteps, TrendCell } from "@fadymondy/nasaq/web";

Quick start

import { ProgressRing, SegmentBar } from "@fadymondy/nasaq/web";

export function Overview() {
  return (
    <div className="flex items-center gap-6">
      <ProgressRing value={72} label="Onboarding" caption="of 25 steps" />
      <SegmentBar
        className="flex-1"
        segments={[
          { id: "organic", label: "Organic", value: 4200 },
          { id: "paid", label: "Paid", value: 2100 },
          { id: "referral", label: "Referral", value: 900 },
        ]}
      />
    </div>
  );
}

Anatomy

SegmentBar               data-slot="segment-bar"
├─ bar (role="img")      the segments; data-slot="segment-bar-segment" on each
└─ ul                    data-slot="segment-bar-legend": swatch, label, value, share
ProgressRing             data-slot="progress-ring" data-tone role="progressbar"
FunnelSteps              data-slot="funnel-steps"
├─ funnel-steps-step     label, count, share of the first step, the bar
├─ funnel-steps-link     conversion and people lost between two steps, the biggest drop badge
└─ funnel-steps-summary  overall conversion
TrendCell                data-slot="trend-cell" data-trend="up|down|flat"

API

SegmentBar

div props plus:

PropTypeDefaultDescription
segments{ id, label, value, color? }[]requiredParts of the whole. Zero and negative values draw nothing but stay in the legend.
totalnumbersum of valuesThe whole. Larger than the sum leaves an empty track (6 of 10 seats).
formatFormatNumberOptionsplain numberIntl options for legend values.
legendbooleantrueLegend with value and share per segment.
inlineLabelsbooleantrueShare inside segments of at least 10%.
patternedbooleanfalseHatch patterns over the fills, so segments differ by more than colour.
size"sm" | "md" | "lg""md"Bar thickness.
labelstringshares summaryAccessible name of the bar.
restLabelReactNodenoneLegend row for the empty track.
labelsPartial<ChartExtrasLabels>en / arText overrides.

ProgressRing

PropTypeDefaultDescription
valuenumberrequiredCurrent value.
max / minnumber100 / 0The range that fills the ring.
tone"default" | "info" | "success" | "warning" | "danger" | "auto""default""auto" turns warning at warnAt and danger at dangerAt of the range.
warnAt / dangerAtnumber0.8 / 0.95Fractions for tone="auto".
sizenumber96Diameter in px.
thicknessnumber8Stroke width in a 100 unit box.
childrenReactNodethe percentageThe middle figure.
captionReactNodenoneSmall text under it.
labelstringrequiredWhat is measured (accessible name).
valueTextstring"% complete"Spoken value.

FunnelSteps

PropTypeDefaultDescription
steps{ id, label, count, detail? }[]requiredIn order, first step is the widest.
formatFormatNumberOptionsplain numberIntl options for counts.
summarybooleantrueOverall conversion line.
labelstring"Funnel steps"Accessible name.

TrendCell

PropTypeDefaultDescription
valuenumber | ReactNoderequiredThe figure.
formatFormatNumberOptionsnoneFor a numeric value.
datareadonly number[]noneValues for the small chart, oldest first.
variant"line" | "bar""line"Sparkline or MiniBar.
deltanumbernoneChange as a fraction (0.124 is +12.4%).
invertbooleanfalseDown is good.
highlightnumberlast barBar to emphasise.
chartLabelstringnoneSpoken summary of the small chart.

Helpers

segmentShares(segments, total?), ringFraction(value, max, min), ringGeometry(fraction, strokeWidth), ringToneFor(fraction, warnAt, dangerAt), funnelBarShare(count, first, min). Pure functions.

Examples

A capacity bar:

import { SegmentBar } from "@fadymondy/nasaq/web";

export const Seats = () => (
  <SegmentBar
    total={20}
    restLabel="Free"
    segments={[
      { id: "admin", label: "Admins", value: 3 },
      { id: "member", label: "Members", value: 11 },
    ]}
  />
);

Usage ring that warns:

import { ProgressRing } from "@fadymondy/nasaq/web";

export const Storage = () => (
  <ProgressRing value={92} tone="auto" label="Storage used" caption="46 of 50 GB" />
);

A table column:

import { TrendCell, type DataTableColumn } from "@fadymondy/nasaq/web";

type Row = { id: string; revenue: number; change: number; weeks: number[] };
export const column: DataTableColumn<Row> = {
  id: "revenue",
  header: "Revenue",
  align: "end",
  cell: (r) => <TrendCell value={r.revenue} format={{ style: "currency", currency: "SAR", maximumFractionDigits: 0 }} delta={r.change} data={r.weeks} chartLabel="Revenue, last 8 weeks" />,
  sortValue: (r) => r.revenue,
};

Arabic:

import { FunnelSteps } from "@fadymondy/nasaq/web";

export const Ar = () => (
  <FunnelSteps
    steps={[
      { id: "visit", label: "زيارة", count: 12000 },
      { id: "cart", label: "إضافة للسلة", count: 3400 },
      { id: "paid", label: "دفع", count: 910 },
    ]}
  />
);

Accessibility

There is no keyboard interaction. The SegmentBar bar is role="img" with a summary of shares (or your label) and the legend is a real list. ProgressRing is a progressbar with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext. Each FunnelSteps step is announced "Step 2 of 4", and the biggest drop is a badge with an icon and text. TrendCell has a visually hidden "up / down / no change" next to its arrow. Localise label, chartLabel, segment labels and labels.

RTL & i18n

  • Bars grow from the inline start, so SegmentBar reads right to left in Arabic; the ring fills the opposite way and the middle text is not mirrored.
  • TrendCell charts run right to left (they reuse Sparkline and MiniBar).
  • Numbers and percentages use the active locale with Western digits, and are bidi-isolated (Num).

Styling & tokens

  • Colours are the chart palette (CHART_COLORS), --primary, --nq-success, --nq-warning, --nq-danger, --nq-info, --nq-surface-soft. Pass token strings in color.
  • Target [data-slot="segment-bar-segment"], [data-slot="progress-ring"][data-tone="danger"], [data-slot="trend-cell"][data-trend="down"]; extend with className.

Do / Don't

  • Do keep segment counts under about six; group the tail as "Other".
  • Do keep the legend on. It is what makes the bar readable without colour.
  • Don't use a ring for something that is not a share of a whole or of a target.
  • Don't put more than one ProgressRing tone meaning on a page without a caption saying what it means.

Lab

https://docs.nasaqui.com/?path=/docs/components-charts-maps-extra-charts--docs

On this page