stacked-progress-bar
joachimbrasier-github/stacked-progress-barFreeComponent
A composable stacked progress bar for shadcn/ui to display multiple statuses in one track, with optional legend, tooltips, and accessible semantics.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/JoachimBrasier/shadcn-stacked-progress-bar/main/stacked-progress-bar.jsonSource
1import { cva, type VariantProps } from "class-variance-authority";2import * as React from "react";3import { cn } from "@/lib/utils";45type StackedProgressBarContextValue = {6 max: number;7 legendId: string | null;8 setLegendId: React.Dispatch<React.SetStateAction<string | null>>;9};1011const StackedProgressBarContext =12 React.createContext<StackedProgressBarContextValue | null>(null);1314function useStackedProgressBarContext(componentName: string) {15 const context = React.use(StackedProgressBarContext);1617 if (!context) {18 throw new Error(19 `${componentName} must be used within StackedProgressBarProvider.`,20 );21 }2223 return context;24}2526export function StackedProgressBarSegment({27 value,28 style,29 className,30 "aria-hidden": ariaHidden,31 ...props32}: { value: number } & React.ComponentProps<"div">) {33 const { max } = useStackedProgressBarContext("StackedProgressBarSegment");34 const safeValue = Number.isFinite(value)35 ? Math.min(Math.max(value, 0), max)36 : 0;3738 return (39 <div40 data-slot="stacked-progress-bar-segment"41 aria-hidden={ariaHidden ?? true}42 {...{ ...props }}43 className={cn("h-full", className)}44 style={{ width: `${(safeValue / max) * 100}%`, ...style }}45 />46 );47}4849export function StackedProgressBar({50 value,51 className,52 role,53 "aria-label": ariaLabel,54 "aria-labelledby": ariaLabelledBy,55 "aria-describedby": ariaDescribedBy,56 "aria-valuemin": ariaValueMin,57 "aria-valuemax": ariaValueMax,58 "aria-valuenow": ariaValueNow,59 "aria-valuetext": ariaValueText,60 ...props61}: { value?: number } & React.ComponentProps<"div">) {62 const context = useStackedProgressBarContext("StackedProgressBar");63 const max = context?.max ?? 100;64 const safeValue =65 value !== undefined && Number.isFinite(value)66 ? Math.min(Math.max(value, 0), max)67 : undefined;6869 return (70 <div71 data-slot="stacked-progress-bar"72 role={role ?? "progressbar"}73 aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : "Progress")}74 aria-labelledby={ariaLabelledBy}75 aria-describedby={ariaDescribedBy ?? context?.legendId ?? undefined}76 aria-valuemin={ariaValueMin ?? 0}77 aria-valuemax={ariaValueMax ?? max}78 aria-valuenow={ariaValueNow ?? safeValue}79 aria-valuetext={ariaValueText}80 {...props}81 className={cn(82 "bg-muted flex h-3 overflow-hidden rounded-full",83// … truncated
What it pulls in
npm packages
Other registry items
