Skip to main content
userTourKit
@tour-kit/adoptionDashboard

Adoption Funnel

Step-by-step adoption funnel with drop-off percentages — Pendo/Userpilot parity, native CSS, no chart peer dependency.

domidex01Published

<AdoptionFunnel> renders a vertical funnel chart with retention and drop-off between adjacent steps. It is data-first: hand it pre-computed steps and it works without any provider. Inside an <AdoptionProvider>, pair it with useFunnelData({ featureIds }) for a one-line in-provider integration.

The funnel is rendered with native CSS — no recharts, d3, or other chart peer dependency. Bundle delta is <2 KB gzipped.

Compute funnel data from your analytics layer and pass it in directly:

import { AdoptionFunnel } from '@tour-kit/adoption'
import '@tour-kit/adoption/styles/funnel.css'

const steps = [
  { id: 'view', label: 'Viewed', entered: 1000, completed: 720 },
  { id: 'click', label: 'Clicked CTA', entered: 720, completed: 380 },
  { id: 'signup', label: 'Signed Up', entered: 380, completed: 240 },
]

<AdoptionFunnel
  steps={steps}
  title="Sign-up funnel"
  onStepClick={(step, index) => console.log('drilldown:', step, index)}
/>

This path needs no provider, so the funnel can live in any tree — admin dashboards, server-rendered reports, etc.

In-provider Usage with useFunnelData

import {
  AdoptionFunnel,
  AdoptionProvider,
  useFunnelData,
} from '@tour-kit/adoption'

function OnboardingFunnel() {
  const steps = useFunnelData({
    featureIds: ['view-pricing', 'start-trial', 'invite-team'],
    labels: {
      'view-pricing': 'Viewed Pricing',
      'start-trial': 'Started Trial',
      'invite-team': 'Invited Team',
    },
  })
  return <AdoptionFunnel steps={steps} title="Activation funnel" />
}

<AdoptionProvider features={features}>
  <OnboardingFunnel />
</AdoptionProvider>

Current-state, not historical. useFunnelData derives a per-user snapshot from useAdoptionStatsentered is the user's useCount and completed is useCount when the feature status is 'adopted', else 0. For aggregated cohort funnels with date ranges, compute them in your analytics layer and hand the result to <AdoptionFunnel steps={...}> directly.

<AdoptionFunnel> Props

Prop

Type

FunnelStep Shape

Prop

Type

useFunnelData Input/Output

Prop

Type

Returns FunnelStep[] ready to pass to <AdoptionFunnel steps={...}>. The source data is in-memory and synchronous, so the hook returns the steps directly — no loading/error envelope.

Accessibility

  • The chart is exposed to assistive tech as a single role="img" element with an auto-generated aria-label summarizing the funnel (Adoption funnel: 100 → 60 → 30, 30% end-to-end retention). Override via the ariaLabel prop.
  • Each bar carries aria-hidden="true" — screen readers receive the same numbers through a visually-hidden <table> mirror placed alongside the visual list.
  • Clickable steps are keyboard-activatable. Enter and Space both fire onStepClick; tab order matches visual order.
  • Honors prefers-reduced-motion: reduce — the hover-transition is disabled under the OS preference. See the reduced-motion guide.

Styling

Import the base stylesheet once at your app root:

import '@tour-kit/adoption/styles/funnel.css'

CSS custom properties for theming:

:root {
  --tour-funnel-gap: 0.5rem;
  --tour-funnel-step-gap: 0.5rem;
  --tour-funnel-bar-bg: hsl(220 90% 56%);
  --tour-funnel-bar-fg: #fff;
  --tour-funnel-retention-fg: hsl(0 0% 40%);
  --tour-funnel-step-hover: rgba(0, 0, 0, 0.04);
  --tour-funnel-focus-ring: hsl(220 90% 56%);
}

Next Steps