Adoption Funnel
Step-by-step adoption funnel with drop-off percentages — Pendo/Userpilot parity, native CSS, no chart peer dependency.
<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.
Provider-less Usage (Recommended)
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 useAdoptionStats — entered 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-generatedaria-labelsummarizing the funnel (Adoption funnel: 100 → 60 → 30, 30% end-to-end retention). Override via theariaLabelprop. - 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
- AdoptionDashboard — full dashboard component
- useAdoptionStats — underlying per-feature stats hook
- Reduced-motion guide — cross-package motion contract