JSPM

awesome-kpi-card

0.1.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 23
    • Score
      100M100P100Q68537F
    • License MIT

    Enterprise-grade KPI Card component for React.

    Package Exports

    • awesome-kpi-card

    Readme

    awesome-kpi-card

    Enterprise-grade KPI Card component for React. Three layout variants (compact, detailed, premium), sparkline, trend arrow, variance badge, RAG status indicator, optional REST data fetching with auto-refresh, and full theming via CSS custom properties — all styles injected at runtime so no CSS import is needed.


    Features

    • 3 variantscompact (tight, label + value + variance), detailed (sparkline + variance line), premium (sparkline + target + previous + all indicators)
    • Trend arrow — ▲ / ▼ / — based on value vs previous, with a configurable dead-zone (trendSensitivity)
    • Variance badge+4.50% / −3.20% coloured by direction, shown in header (compact) or value row (detailed/premium)
    • RAG status — colour-coded dot + label driven by value / target ratio against configurable thresholds
    • SVG sparkline — polyline chart from history array, with optional animated draw
    • REST data fetchingendpoint prop + autoRefresh polling; local data prop always takes precedence
    • transform hook — normalise any remote payload shape before rendering
    • onClick callback — receives the fully resolved data object
    • 4 built-in themesdark, light, purple plus the default — all driven by CSS custom properties
    • Self-contained — styles injected at runtime; no CSS import, no sub-folder dependencies
    • ESM + CJS dual build — works in Vite, Next.js, CRA, and any modern bundler
    • Zero runtime dependencies beyond React

    Installation

    npm install awesome-kpi-card
    # or
    yarn add awesome-kpi-card
    # or
    pnpm add awesome-kpi-card

    Peer dependencies — React ≥ 17 and ReactDOM ≥ 17 must already be installed.


    Quick Start

    No CSS import needed — styles are injected automatically on first render.

    import AwesomeKpiCard from 'awesome-kpi-card';
    
    export default function App() {
      return (
        <AwesomeKpiCard
          variant="premium"
          data={{
            label:    'Revenue',
            value:    5200000,
            target:   5000000,
            previous: 4800000,
            history:  [4000000, 4200000, 4500000, 4800000, 5200000],
          }}
          format="currency"
          currency="USD"
          thresholds={{ good: 1, warning: 0.85 }}
          animated
        />
      );
    }

    Both import styles work:

    // Default import
    import AwesomeKpiCard from 'awesome-kpi-card';

    Props

    Prop Type Default Description
    variant 'compact' | 'detailed' | 'premium' 'detailed' Controls layout, density, and which elements are shown by default.
    label string 'KPI Metric' KPI title label shown in the card header.
    value number 0 Current KPI value.
    target number Target value. Used for variance, RAG status, and the target line in premium.
    previous number Previous period value. Used for the trend arrow direction.
    history number[] Array of historical values for the sparkline (oldest → newest).
    data object Local data object with any of { label, value, target, previous, history }. Takes precedence over endpoint.
    endpoint string REST URL to fetch KPI data from. Response root or .data key is used.
    method string 'GET' HTTP method for the endpoint request.
    autoRefresh number Polling interval in ms. Requires endpoint.
    transform (normalized, raw) => object Transforms the remote payload before it is merged into the card's data.
    thresholds { good: number, warning: number } { good: 1, warning: 0.85 } RAG ratio thresholds. good = value/target ≥ good, warning = ≥ warning.
    format 'number' | 'currency' | 'percent' 'number' Value display format.
    currency string 'USD' ISO currency code for format="currency".
    showSparkline boolean variant default Override sparkline visibility.
    showVariance boolean variant default Override variance badge visibility.
    showTrend boolean true Show/hide the trend arrow.
    showTarget boolean variant default Show the target meta line (on by default in premium).
    showPrevious boolean variant default Show the previous meta line (on by default in premium).
    animated boolean false Animate the sparkline draw on mount.
    trendSensitivity number 0 Dead-zone delta — differences ≤ this value show neutral instead of ▲/▼.
    statusLabels { good?: string, warning?: string, critical?: string } Override the default RAG status label strings.
    onClick (data) => void Fired when the card is clicked. Receives the fully resolved data object.
    className string Additional CSS class on the root <section>.
    style object Inline styles on the root element.

    Variant defaults

    Feature compact detailed premium
    showSparkline false true true
    showVariance true true true
    showTarget false false true
    showPrevious false false true

    Examples

    Example 1 — Three variants side by side

    import AwesomeKpiCard from 'awesome-kpi-card';
    
    var kpiData = {
      label:    'Monthly Revenue',
      value:    5200000,
      target:   5000000,
      previous: 4800000,
      history:  [3800000, 4100000, 4400000, 4700000, 4900000, 5200000],
    };
    
    var thresholds = { good: 1, warning: 0.9 };
    
    export default function VariantsDemo() {
      return (
        <div style={{ display: 'flex', gap: 20, padding: 32, background: '#10151c', flexWrap: 'wrap' }}>
    
          <div style={{ width: 260 }}>
            <AwesomeKpiCard
              variant="compact"
              data={kpiData}
              format="currency"
              thresholds={thresholds}
            />
          </div>
    
          <div style={{ width: 300 }}>
            <AwesomeKpiCard
              variant="detailed"
              data={kpiData}
              format="currency"
              thresholds={thresholds}
              animated
            />
          </div>
    
          <div style={{ width: 340 }}>
            <AwesomeKpiCard
              variant="premium"
              data={kpiData}
              format="currency"
              thresholds={thresholds}
              animated
            />
          </div>
    
        </div>
      );
    }

    Example 2 — Live REST API with auto-refresh and custom status labels

    import AwesomeKpiCard from 'awesome-kpi-card';
    
    export default function LiveKpi() {
      return (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 280px)', gap: 20, padding: 32, background: '#0a0f16' }}>
    
          <AwesomeKpiCard
            variant="premium"
            endpoint="/api/kpi/revenue"
            autoRefresh={30000}
            format="currency"
            currency="USD"
            thresholds={{ good: 1, warning: 0.9 }}
            statusLabels={{ good: 'Exceeding', warning: 'Near Miss', critical: 'Behind' }}
            animated
          />
    
          <AwesomeKpiCard
            variant="detailed"
            endpoint="/api/kpi/nps"
            autoRefresh={60000}
            format="number"
            thresholds={{ good: 0.9, warning: 0.75 }}
            statusLabels={{ good: 'Excellent', warning: 'Acceptable', critical: 'Poor' }}
          />
    
          <AwesomeKpiCard
            variant="detailed"
            endpoint="/api/kpi/uptime"
            autoRefresh={10000}
            format="percent"
            thresholds={{ good: 0.999, warning: 0.995 }}
            statusLabels={{ good: 'Healthy', warning: 'Degraded', critical: 'Down' }}
          />
    
        </div>
      );
    }

    Example 3 — onClick, transform, and a custom side panel

    Demonstrates transforming a non-standard API response and handling card clicks with a detail drawer.

    import { useState } from 'react';
    import AwesomeKpiCard from 'awesome-kpi-card';
    
    // The API returns: { metric: "...", current: 123, goal: 100, trend: [...] }
    // We use `transform` to map it to the expected shape.
    function transformApiResponse(normalized) {
      return {
        label:   normalized.metric,
        value:   normalized.current,
        target:  normalized.goal,
        history: normalized.trend,
      };
    }
    
    var kpis = [
      { id: 'cac',        label: 'Customer Acq. Cost',  value: 84,      target: 90,      previous: 91,      history: [100, 96, 93, 91, 88, 84],      format: 'currency' },
      { id: 'churn',      label: 'Monthly Churn',        value: 0.021,   target: 0.025,   previous: 0.028,   history: [0.04, 0.035, 0.03, 0.028, 0.025, 0.021], format: 'percent' },
      { id: 'arpu',       label: 'ARPU',                 value: 142,     target: 130,     previous: 128,     history: [110, 118, 124, 128, 135, 142],  format: 'currency' },
      { id: 'activation', label: 'Activation Rate',      value: 0.712,   target: 0.70,    previous: 0.68,    history: [0.61, 0.64, 0.67, 0.68, 0.70, 0.712], format: 'percent' },
    ];
    
    var drawerStyle = {
      position: 'fixed', top: 0, right: 0, width: 340,
      height: '100vh', background: '#111827',
      borderLeft: '1px solid rgba(255,255,255,0.08)',
      padding: 32, zIndex: 100, color: '#f7f3e8',
      fontFamily: 'sans-serif', overflowY: 'auto',
      display: 'flex', flexDirection: 'column', gap: 16,
    };
    
    export default function KpiDashboard() {
      var [selected, setSelected] = useState(null);
    
      return (
        <div style={{ padding: 32, background: '#0a0f16', minHeight: '100vh' }}>
          <h2 style={{ color: '#f7f3e8', fontFamily: 'sans-serif', marginBottom: 24 }}>Growth Metrics</h2>
    
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px,1fr))', gap: 20 }}>
            {kpis.map(function(kpi) {
              return (
                <AwesomeKpiCard
                  key={kpi.id}
                  variant="detailed"
                  label={kpi.label}
                  value={kpi.value}
                  target={kpi.target}
                  previous={kpi.previous}
                  history={kpi.history}
                  format={kpi.format}
                  thresholds={{ good: 1, warning: 0.9 }}
                  animated
                  onClick={function(data) { setSelected({ ...kpi, resolved: data }); }}
                />
              );
            })}
          </div>
    
          {selected && (
            <div style={drawerStyle}>
              <button
                onClick={function() { setSelected(null); }}
                style={{ alignSelf: 'flex-end', background: 'transparent', border: '1px solid rgba(255,255,255,0.15)', color: '#fff', borderRadius: 4, width: 28, height: 28, cursor: 'pointer' }}
              ></button>
    
              <div style={{ fontSize: 22, fontWeight: 700 }}>{selected.label}</div>
              <div style={{ fontSize: 13, color: 'rgba(247,243,232,0.6)' }}>Format: {selected.format}</div>
    
              <div style={{ height: 1, background: 'rgba(255,255,255,0.08)' }} />
    
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8, fontSize: 13 }}>
                <div>Current: <strong>{String(selected.value)}</strong></div>
                <div>Target: <strong>{String(selected.target)}</strong></div>
                <div>Previous: <strong>{String(selected.previous)}</strong></div>
              </div>
    
              <div style={{ marginTop: 'auto', fontSize: 11, color: 'rgba(255,255,255,0.2)', fontFamily: 'monospace' }}>
                ID: {selected.id}
              </div>
            </div>
          )}
        </div>
      );
    }

    Theming

    All colours are CSS custom properties. Apply a theme class to a wrapper element:

    <div class="theme-dark">  <!-- or theme-light / theme-purple -->
      ...
    </div>

    Or override the variables directly:

    :root {
      --kpi-bg:       #0a0f16;
      --kpi-text:     #f7f3e8;
      --kpi-positive: #4cd39b;  /* RAG good / positive variance */
      --kpi-negative: #ff6a6a;  /* RAG critical / negative variance */
      --kpi-warning:  #f1b463;  /* RAG warning */
      --kpi-border:   rgba(255,255,255,0.08);
      --kpi-muted:    rgba(247,243,232,0.7);
      --kpi-panel:    rgba(13,18,26,0.92);
    }

    The --kpi-accent variable is set automatically per-card to the current RAG colour and drives the card glow.

    Built-in theme classes

    Class Background Accent
    (default / dark) #10151c #4cd39b / #ff6a6a / #f1b463
    .theme-light #f6f6f2 #1a9b64 / #e15656 / #cf8a3a
    .theme-dark #0a0f16 #4cd39b / #ff6a6a / #f1b463
    .theme-purple #1a0d2e #5ee6b8 / #ff7aa2 / #f2c264

    License

    MIT