Component library

Showing 11 components with role chart.

Dashboard

  • <MaturityRadar>

    sharedChartContentDashboard

    Radar chart of dimensions (axes) vs. maturity score (radial). Optional target overlay.

    When to use: Use to show a multi-dimensional capability assessment, typically in 'current state' or 'executive summary' sections. Works for SEO maturity too (e.g. Technical, Content, Authority, Measurement, Governance as axes), where the pillar bars of <PillarScoreCard> would be too coarse.

    Preview

    Acme automation maturity — current vs. 6-month target

    Scores from 11 stakeholder interviews using the Lunnoa maturity framework (1 = ad hoc, 5 = optimised).

    Current Target
    PropTypeNotes
    dimensionsstring[]Required. Axis labels, in order.Example: ["Data", "Tooling", "Process", "Governance", "Skills"]
    currentnumber[]Required. Current scores, same order as dimensions.Example: [3, 2, 3, 2, 2]
    targetnumber[]Optional. Optional target scores, drawn as a dashed overlay.
    maxnumberOptional. Default: 5. Maximum value on the radial axis.
    titlestringOptional. Chart title.
    descriptionstringOptional. Subtitle / methodology note.

    Examples

    <MaturityRadar
        dimensions={["Data quality", "Tooling", "Process clarity", "Governance", "Automation skills"]}
        current={[3, 2, 3, 2, 2]}
        target={[4, 4, 4, 4, 3]}
        title="Acme automation maturity — current vs. 6-month target"
        description="Scores from 11 stakeholder interviews using the Lunnoa maturity framework (1 = ad hoc, 5 = optimised)."
    />
  • <MaturityHeatmap>

    sharedChartContentDataDashboard

    Stage-based maturity table (rows = dimensions, columns = levels). One highlighted cell per row.

    When to use: Use as an alternative to MaturityRadar when the maturity framework is stage-based (e.g. CMMI-style: ad hoc / repeatable / defined / managed / optimised).

    Preview

    Current vs 6-month target

    DimensionAd hocRepeatableDefinedManagedOptimised
    Data quality
    Tooling
    Current Target
    PropTypeNotes
    rowsstring[]Required. Row labels (dimensions).Example: ["Data quality", "Tooling", "Process clarity"]
    columnsstring[]Required. Column labels (maturity levels).Example: ["Ad hoc", "Repeatable", "Defined", "Managed", "Optimised"]
    currentboolean[][]Required. 2D array [row][col]. Each row should have at most one true cell.
    targetboolean[][]Optional. Optional target cells, drawn as a ring.
    titlestringOptional. Chart title.

    Examples

    <MaturityHeatmap
        rows={["Data quality", "Tooling"]}
        columns={["Ad hoc", "Repeatable", "Defined", "Managed", "Optimised"]}
        current={[[false, false, true, false, false], [false, true, false, false, false]]}
        target={[[false, false, false, true, false], [false, false, false, true, false]]}
        title="Current vs 6-month target"
    />
  • <OpportunityMatrix>

    sharedChartCompareContentDashboard

    Effort × impact scatter plot (effort increases left to right, impact increases bottom to top). Top-left (low effort, high impact) is the usual quick-win zone. Optional category (or name) tabs match the DataTable filter pattern.

    When to use: Use to visualise a portfolio of candidate use cases / opportunities scored on two dimensions. Typically immediately before the recommended use case grid. Also fits SEO analyses: plot keyword clusters or content opportunities as effort × impact, with categories like Technical, Content, and Authority as tabs.

    Preview

    Twelve use cases scored on effort and impact

    FinanceOperationsPeople

    Portfolio by function

    FinanceOperations
    PropTypeNotes
    items{ name: string; effort: number; impact: number; category?: string }[]Required. Each item is plotted as a dot. effort and impact are 1–5.
    titlestringOptional. Chart title.
    descriptionstringOptional. Subtitle.
    tabs{ id: string; label: string }[]Optional. Optional filter tabs (same pattern as DataTable). Include `{ id: "all", label: "All" }` first. Other tab ids slug-match `tabFilterKey` on each item (default: category names, e.g. `finance` for Finance).
    tabFilterKey"category" | "name"Optional. Default: category. Which item field tab ids match after slugify.Values: category, name

    Examples

    <OpportunityMatrix
        title="Twelve use cases scored on effort and impact"
        items={[
            { name: "Supplier invoice intake", effort: 2, impact: 5, category: "Finance" },
            { name: "Order acknowledgements", effort: 2, impact: 4, category: "Operations" },
            { name: "HR ticket triage", effort: 1, impact: 3, category: "People" }
        ]}
    />
    <OpportunityMatrix
        title="Portfolio by function"
        tabs={[
            { id: "all", label: "All" },
            { id: "finance", label: "Finance" },
            { id: "operations", label: "Operations" }
        ]}
        items={[
            { name: "Invoice intake", effort: 2, impact: 5, category: "Finance" },
            { name: "Order acknowledgements", effort: 2, impact: 4, category: "Operations" }
        ]}
    />
  • <ComparisonBar>

    sharedChartCompareDashboard

    Horizontal grouped bar chart: one row per process, with a grey Before bar and a coloured After bar. Before/After legend is rendered automatically below the chart.

    When to use: Use to project the impact of a wave of automation across multiple processes. Most useful immediately after a use case grid. Put the process or use-case name in each row's `label` (Y-axis). Do not use Before/After wording such as "Manual today" or "After automation" in `label`; those states are already shown by bar colour and the chart legend. In SEO reports, use it to benchmark against a competitor per metric or to project measured baseline vs target (e.g. clicks per topic cluster).

    Often with: UseCaseGridBeforeAfter

    Preview

    Manual hours per month — before vs. projected after Wave 1

    BeforeAfter
    PropTypeNotes
    rows{ label: string; before: number; after: number }[]Required. One object per process being compared. Each row renders once on the Y-axis with two grouped bars (before, then after).
    rows[].labelstringRequired. Process or use-case name shown on the Y axis (e.g. "Supplier invoice intake"). Not the Before/After state.Example: Order acknowledgements
    rows[].beforenumberRequired. Current / baseline numeric value. Rendered as the grey bar.Example: 280
    rows[].afternumberRequired. Projected / proposed numeric value. Rendered as the coloured After bar.Example: 60
    unitstringOptional. Default: "". Suffix for tick labels and tooltips.Example: hrs
    isPositiveDirection"higher" | "lower"Optional. Default: lower. Whether smaller numbers are better. Drives the After bar colour.Values: higher, lowerExample: lower
    titlestringOptional. Chart title.
    descriptionstringOptional. Subtitle / methodology note.

    Examples

    <ComparisonBar
        title="Manual hours per month — before vs. projected after Wave 1"
        unit=" hrs"
        isPositiveDirection="lower"
        rows={[
            { label: "Supplier invoice intake", before: 280, after: 60 },
            { label: "Order acknowledgements", before: 110, after: 20 }
        ]}
    />
  • <UsageDonutCard>

    sharedChartDashboard

    Donut chart with centre headline figures, a breakdown list (avatar initials, title, subtitle, coloured dot and usage line), and an optional footer link.

    When to use: Use when a report needs a share-style visual (usage by vendor, cost by workstream, incidents by severity). Pass numeric `segments[].value` for slice proportions; `rows[].usageDisplay` is free-form text for the right column. Prefer 3–5 segments for legibility. In SEO reports, use it for traffic share by channel (organic, direct, paid, referral) or organic traffic share by site section.

    Preview

    API token usages

    13.5M

    2 450 keys

    • GPT

      2 API keys configured

      7M

      Tokens used

    • Gemini

      1 API key configured

      2.5M

      Tokens used

    • xAI

      2 API keys configured

      4.5M

      Tokens used

    PropTypeNotes
    titlestringRequired. Card title.Example: API token usages
    centerValuestringRequired. Large text in the donut centre.Example: 13.5M
    centerSubtextstringOptional. Muted line under the centre value.Example: 2 450 API keys
    segments{ id: string; value: number; color: "brand"|"purple"|"sky"|"fuchsia"|"emerald" }[]Required. Slice weights and semantic colours (maps to theme tokens).
    rows{ segmentId: string; title: string; subtitle: string; usageDisplay: string; avatarText?: string; usageCaption?: string }[]Required. One row per slice; `segmentId` must match a `segments[].id` for the dot colour.
    footerLabelstringOptional. Link text below the list.
    footerHrefstringOptional. URL for the footer link (internal or external).
    showMenubooleanOptional. Default: true. Show the illustrative kebab button.

    Examples

    <UsageDonutCard
        title="API token usages"
        centerValue="13.5M"
        centerSubtext="2 450 keys"
        segments={[
            { id: "gpt", value: 7, color: "brand" },
            { id: "gemini", value: 2.5, color: "purple" },
            { id: "xai", value: 4.5, color: "sky" }
        ]}
        rows={[
            { segmentId: "gpt", avatarText: "GP", title: "GPT", subtitle: "2 API keys configured", usageDisplay: "7M" },
            { segmentId: "gemini", avatarText: "Ge", title: "Gemini", subtitle: "1 API key configured", usageDisplay: "2.5M" },
            { segmentId: "xai", avatarText: "xA", title: "xAI", subtitle: "2 API keys configured", usageDisplay: "4.5M" }
        ]}
        footerLabel="View all usage details"
        footerHref="#"
    />
  • <FinanceOverviewCard>

    financeStatsChartDashboard

    Two-column financial headline: left block (title, date range, total revenue with optional delta and footnote), right block (product condition headline, optional trend pill, year selector, multi-series monotone area chart), plus a three-column footer row for supporting metrics.

    When to use: Use for executive-style revenue or adoption snapshots in report readouts. Pass `chartMonths` and aligned `chartSeries[].values`; include at least one series (empty shows a muted placeholder). Keep series count to 2–4 for clarity. Footer `stats` should contain exactly three items.

    Preview

    Financial income

    1 Aug 2025 – 1 Nov 2025

    Total revenue+9.78%

    £8,240.00

    Increased 15% from last month

    Product condition

    75%2.8%

    Selling product

    £335,000

    Followers

    1,500

    Campaign

    560

    PropTypeNotes
    dateRangestringRequired. Human-readable range under the income title.Example: 1 Aug 2025 – 1 Nov 2025
    totalRevenueValuestringRequired. Large headline currency string.Example: £8,240.00
    incomeTitlestringOptional. Default: "Financial income". Left column title.
    totalRevenueLabelstringOptional. Default: "Total revenue". Label above the headline figure.
    totalRevenueDeltastringOptional. Optional percentage chip; leading + uses success colour, leading − uses error.
    totalRevenueFootnotestringOptional. Muted line under the revenue figure.
    conditionValuestringRequired. Large headline next to the chart header.Example: 75%
    conditionTitlestringOptional. Default: "Product condition". Muted label above the condition value.
    conditionBadgeTextstringOptional. Pill text beside the condition value.Example: 2.8%
    conditionBadgeTrend"up" | "down"Optional. Default: down. Arrow direction inside the pill.Values: up, down
    yearsstring[]Optional. Default: ["2025"]. Year `<select>` options.
    chartMonthsstring[]Required. X-axis labels in order (e.g. Jan … Jul).
    chartSeries{ name: string; values: number[]; colorKey: "brand"|"sky"|"slate" }[]Required. One or more series; each `values` array must match `chartMonths` length. If empty, a muted placeholder is shown instead of the chart.
    stats{ label: string; value: string; labelTone?: "brand"|"sky"|"emerald" }[]Required. Exactly three footer metrics.

    Examples

    <FinanceOverviewCard
        dateRange="1 Aug 2025 – 1 Nov 2025"
        totalRevenueDelta="+9.78%"
        totalRevenueValue="£8,240.00"
        totalRevenueFootnote="Increased 15% from last month"
        conditionValue="75%"
        conditionBadgeText="2.8%"
        years={["2024", "2025", "2026"]}
        chartMonths={["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]}
        chartSeries={[
            { name: "Series A", values: [1200, 1800, 2200, 2600, 3000, 3400, 3800], colorKey: "sky" },
            { name: "Series B", values: [800, 1100, 1400, 1700, 2100, 2500, 2900], colorKey: "brand" },
            { name: "Series C", values: [400, 500, 600, 700, 800, 900, 1000], colorKey: "slate" }
        ]}
        stats={[
            { label: "Selling product", value: "£335,000", labelTone: "sky" },
            { label: "Followers", value: "1,500", labelTone: "sky" },
            { label: "Campaign", value: "560", labelTone: "emerald" }
        ]}
    />
  • <AllocationDriftChart>

    financeChartDataDashboard

    Current vs target allocation table with drift, tolerance band status (in band / overweight / underweight), and inline weight bars.

    When to use: Use in portfolio monitoring or rebalancing reports to show how each sleeve drifts from strategic targets. Pass weights as numbers (typically percent). Set `tolerance` per row when bands differ by asset class.

    Often with: ComparisonBarUsageDonutCardSimpleDataTable

    Preview

    Strategic allocation drift

    Tolerance band ±1% unless noted

    Asset classCurrentTargetDriftStatusWeight
    Global equities42.3%40.0%+2.3%Overweight
    Investment grade credit24.1%25.0%-0.9%In band
    Private markets18.6%20.0%-1.4%In band
    Cash8.2%10.0%-1.8%Underweight
    Alternatives6.8%5.0%+1.8%Overweight
    Current weight Target weight
    PropTypeNotes
    titlestringOptional. Chart heading.
    descriptionstringOptional. Muted subheading.
    rows{ label: string; current: number; target: number; tolerance?: number }[]Required. One row per asset class or sleeve. `tolerance` defaults to 1 (same unit as weights).
    unitstringOptional. Default: "%". Suffix for weight and drift columns.

    Examples

    <AllocationDriftChart
      title="Strategic allocation drift"
      description="Tolerance band ±1% unless noted"
      rows={[
        { label: "Global equities", current: 42.3, target: 40, tolerance: 1 },
        { label: "Investment grade credit", current: 24.1, target: 25, tolerance: 1 },
        { label: "Private markets", current: 18.6, target: 20, tolerance: 2 },
        { label: "Cash", current: 8.2, target: 10, tolerance: 1 },
        { label: "Alternatives", current: 6.8, target: 5, tolerance: 1 }
      ]}
    />
  • <PillarScoreCard>

    seoStatsChartDashboard

    Lighthouse-style score gauge: an overall 0–100 ring (green ≥ 80, amber ≥ 50, red below) plus horizontal sub-score bars per pillar. Domain-neutral — use for SEO, GEO/AEO, maturity, or any multi-pillar assessment.

    When to use: Use once at the top of an executive summary as the headline verdict. Works for SEO analysis (Technical, Content, Authority), combined SEO/GEO/AEO scores, organisational maturity, or any scored assessment with 2–5 pillars. Scores must come from a real audit or documented method; never invent them. `<SeoScoreCard>` is a deprecated alias with the same props.

    Often with: SeoAuditChecklistCoreWebVitalsCardKPIGridMaturityRadar

    Preview

    Combined visibility score

    Weighted score from the 7 Jul 2026 site crawl and AI citation audit

    Assessed 7 Jul 2026

    SEO / GEO / AEO

    • SEO80

      Strong technical base; one broken footer link

    • GEO80
    • AEO60

      Schema present but thin entity coverage

    SEO health score

    Weighted score across four pillars, from the June 2026 crawl of 1,240 pages

    Crawled 14 Jun 2026

    Overall score

    • Technical48

      Crawl budget wasted on 3,100 parameter URLs

    • Content71
    • Authority66
    • Experience58

      INP fails on mobile product pages

    PropTypeNotes
    scorenumberRequired. Overall score 0–100 (clamped).Example: 62
    scoreLabelstringOptional. Default: "Overall score". Label beside the pillar bars.Example: Combined SEO / GEO / AEO
    titlestringOptional. Card heading.Example: Site visibility score
    descriptionstringOptional. Muted subheading, e.g. the scoring method.
    asOfstringOptional. Assessment date label shown top-right.Example: Crawled 14 Jun 2026
    pillars{ label: string; score: number; note?: string }[]Optional. Category sub-scores (0–100), typically 2–5 pillars (e.g. SEO, GEO, AEO or Technical, Content, Authority).

    Examples

    <PillarScoreCard
        title="Combined visibility score"
        scoreLabel="SEO / GEO / AEO"
        description="Weighted score from the 7 Jul 2026 site crawl and AI citation audit"
        asOf="Assessed 7 Jul 2026"
        score={73}
        pillars={[
            { label: "SEO", score: 80, note: "Strong technical base; one broken footer link" },
            { label: "GEO", score: 80 },
            { label: "AEO", score: 60, note: "Schema present but thin entity coverage" }
        ]}
    />
    <PillarScoreCard
        title="SEO health score"
        description="Weighted score across four pillars, from the June 2026 crawl of 1,240 pages"
        asOf="Crawled 14 Jun 2026"
        score={62}
        pillars={[
            { label: "Technical", score: 48, note: "Crawl budget wasted on 3,100 parameter URLs" },
            { label: "Content", score: 71 },
            { label: "Authority", score: 66 },
            { label: "Experience", score: 58, note: "INP fails on mobile product pages" }
        ]}
    />
  • <SerpPositionDistribution>

    seoChartStatsDashboard

    Bar chart of keyword counts per SERP position bucket (e.g. Top 3, 4–10, 11–20, 21–50, 51–100), with an optional muted comparison series for the previous crawl.

    When to use: Use to show the shape of the ranking profile and how it shifted, typically right after the headline KPIs in an SEO report. Buckets are free-form labels, so it also works for striking-distance analyses (positions 11–20).

    Often with: KeywordRankingTableTrafficTrendChartKPIGrid

    Preview

    Keyword distribution by SERP position

    Tracked keyword set, June vs March 2026

    Mar 2026 Jun 2026
    PropTypeNotes
    titlestringOptional. Chart heading.Example: Keyword distribution by SERP position
    descriptionstringOptional. Muted subheading.
    buckets{ label: string; count: number; previousCount?: number }[]Required. Buckets in display order. previousCount adds a grey comparison bar.
    currentLabelstringOptional. Default: "Current". Legend label for the current series.
    previousLabelstringOptional. Default: "Previous". Legend label for the comparison series.

    Examples

    <SerpPositionDistribution
        title="Keyword distribution by SERP position"
        description="Tracked keyword set, June vs March 2026"
        currentLabel="Jun 2026"
        previousLabel="Mar 2026"
        buckets={[
            { label: "Top 3", count: 12, previousCount: 8 },
            { label: "4–10", count: 34, previousCount: 29 },
            { label: "11–20", count: 58, previousCount: 61 },
            { label: "21–50", count: 71, previousCount: 78 },
            { label: "51–100", count: 44, previousCount: 52 }
        ]}
    />
  • <TrafficTrendChart>

    seoChartDashboard

    Multi-series area chart over time for traffic-style metrics: organic sessions, clicks, impressions, or conversions, with automatic k/M axis formatting and a legend built from series names.

    When to use: Use to show organic performance over the last 6–12 periods, e.g. GSC clicks and impressions or GA4 sessions. Keep to 1–3 series so the story stays readable; name the data source and window in `sourceNote`. For financial revenue snapshots prefer `<FinanceOverviewCard>`.

    Often with: SerpPositionDistributionKPIGridFinanceOverviewCard

    Preview

    Organic clicks and impressions, 12 months

    Impressions ClicksSource: Google Search Console, 12 months to Jun 2026
    PropTypeNotes
    titlestringOptional. Chart heading.Example: Organic clicks and impressions, 12 months
    descriptionstringOptional. Muted subheading.
    labelsstring[]Required. X-axis labels in order (months, weeks).Example: ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
    series{ name: string; values: number[]; color?: "brand" | "sky" | "emerald" | "purple" | "slate" }[]Required. Each values array must match labels length. Colours default to the palette order when omitted.
    unitstringOptional. Default: "". Suffix appended to axis ticks and tooltip values.
    sourceNotestringOptional. Caption under the legend.Example: Source: Google Search Console, 12 months to Jun 2026

    Examples

    <TrafficTrendChart
        title="Organic clicks and impressions, 12 months"
        sourceNote="Source: Google Search Console, 12 months to Jun 2026"
        labels={["Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun"]}
        series={[
            { name: "Impressions", values: [82000, 85000, 91000, 96000, 90000, 84000, 98000, 104000, 112000, 118000, 121000, 127000], color: "sky" },
            { name: "Clicks", values: [2400, 2600, 2900, 3100, 2800, 2500, 3200, 3500, 3900, 4200, 4400, 4700], color: "brand" }
        ]}
    />
  • <TrendChart>

    sharedChartDashboard

    Multi-series line or combo bar-and-line chart over time for document reports, with optional dual Y-axes, grouped bars, and a source caption.

    When to use: Operational and analytical reports: trends over weeks or quarters, adoption curves, revenue vs margin. Set `type="bar"` on a series for columns; `yAxis="right"` for a secondary scale (e.g. £m bars + % line). Prefer `<TrafficTrendChart>` for SEO traffic area charts. For presentation slides use `<TrendLineChart>` (`kind: "presentation"`).

    Often with: TrafficTrendChartComparisonBarFinanceOverviewCardTrendLineChart

    Preview

    Manual hours per week

    ActualTargetBaseline measured in week 1

    Revenue and EBITDA margin

    RevenueEBITDA margin · right axisSource: management accounts, FY26
    PropTypeNotes
    titlestringOptional. Chart heading.
    descriptionstringOptional. Muted subheading under the title.
    labelsstring[]Required. X-axis labels in order (months, weeks, quarters).
    series{ name: string; values: number[]; color?: "brand" | "sky" | "emerald" | "purple" | "slate" | "success" | "warning" | "error"; type?: "line" | "bar"; yAxis?: "left" | "right"; unit?: string }[]Required. One or more series aligned to `labels`. Set `type="bar"` for columns; `yAxis="right"` for the secondary axis.
    unitstringOptional. Default: "". Default unit suffix for the left axis and series without their own `unit`.
    yAxes{ left?: { unit?: string; maxValue?: number; minValue?: number }; right?: { unit?: string; maxValue?: number; minValue?: number } }Optional. Per-axis unit and scale overrides for dual-axis charts.
    sourceNotestringOptional. Caption under the legend naming tool and date.Example: Source: ERP export, FY26 Q1–Q4

    Examples

    <TrendChart
      title="Manual hours per week"
      unit="h"
      labels={["Wk 1", "Wk 2", "Wk 3", "Wk 4", "Wk 5", "Wk 6"]}
      series={[
        { name: "Actual", values: [142, 138, 121, 98, 76, 60], color: "brand" },
        { name: "Target", values: [120, 115, 100, 80, 60, 45], color: "slate" }
      ]}
      sourceNote="Baseline measured in week 1"
    />
    <TrendChart
      title="Revenue and EBITDA margin"
      labels={["Q1", "Q2", "Q3", "Q4"]}
      yAxes={{ left: { unit: "m" }, right: { unit: "%", maxValue: 40 } }}
      series={[
        { name: "Revenue", type: "bar", values: [18, 22, 24, 26], color: "brand", unit: "m" },
        { name: "EBITDA margin", type: "line", yAxis: "right", values: [22, 24, 25, 27], color: "success", unit: "%" }
      ]}
      sourceNote="Source: management accounts, FY26"
    />