Recruitment funnel
Applicants at each stage and the drop-off between.
Built with
Recruitment funnel
Q3 2026 · 14 open roles across 6 teams
Hires
18
Target 20 this quarter
Time to hire
32 days
Median, application to offer
Offer acceptance
69%
18 of 26 offers
Cost per hire
$4,850
Agency fees and ads
1,240 people applied and 18 were hired, 1.5% overall. The biggest drop is from interview to offer, where 85% do not move on.
View data as a table
| Step | Candidates | Conversion | Drop-off | Of first stage |
|---|---|---|---|---|
| Applied | 1,240 | 100% | ||
| Screened | 486 | 39.2% | 60.8% | 39.2% |
| Interviewed | 168 | 34.6% | 65.4% | 13.5% |
| Offered | 26 | 15.5% | 84.5% | 2.1% |
| Hired | 18 | 69.2% | 30.8% | 1.5% |
Busiest open roles
- Senior backend engineerEngineering · 214 applicantsFinal interviews
- Customer success managerCustomer · 132 applicantsOffer sent
- Payroll specialistPeople Ops · 58 applicantsScreening
- Product designerDesign · 187 applicantsPaused
recruitment-funnel.tsx
import { Badge, FunnelChart, MetricMini } from "@nexera-ui/react";
// Q3 2026 hiring at Northwind: every candidate who applied to one of the 14 open roles.
const STAGES = [
{ name: "Applied", value: 1240 },
{ name: "Screened", value: 486 },
{ name: "Interviewed", value: 168 },
{ name: "Offered", value: 26 },
{ name: "Hired", value: 18 },
];
const ROLES = [
{
title: "Senior backend engineer",
team: "Engineering",
applicants: 214,
stage: "Final interviews",
tone: "info",
},
{
title: "Customer success manager",
team: "Customer",
applicants: 132,
stage: "Offer sent",
tone: "success",
},
{
title: "Payroll specialist",
team: "People Ops",
applicants: 58,
stage: "Screening",
tone: "neutral",
},
{ title: "Product designer", team: "Design", applicants: 187, stage: "Paused", tone: "warning" },
] as const;
/** Recruitment funnel: candidates at each hiring stage this quarter, the drop-off between stages and the open roles behind them. */
export default function RecruitmentFunnel() {
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<div className="mx-auto grid max-w-6xl gap-6">
<header className="grid gap-1">
<h2 className="text-heading-h2 text-primary">Recruitment funnel</h2>
<p className="text-body-default text-secondary">Q3 2026 · 14 open roles across 6 teams</p>
</header>
<div className="grid grid-cols-2 gap-4 rounded-lg border border-default bg-surface p-4 @3xl:grid-cols-4 @3xl:p-6">
<MetricMini label="Hires" value="18" caption="Target 20 this quarter" />
<MetricMini label="Time to hire" value="32 days" caption="Median, application to offer" />
<MetricMini label="Offer acceptance" value="69%" caption="18 of 26 offers" />
<MetricMini label="Cost per hire" value="$4,850" caption="Agency fees and ads" />
</div>
<div className="grid gap-4 @5xl:grid-cols-[3fr_2fr]">
<FunnelChart
title="Candidates by stage"
description="Share shown is the conversion from the stage before"
summary="1,240 people applied and 18 were hired, 1.5% overall. The biggest drop is from interview to offer, where 85% do not move on."
stages={STAGES}
valueLabel="Candidates"
/>
<section
aria-labelledby="open-roles"
className="grid content-start gap-3 rounded-lg border border-default bg-surface p-4 @3xl:p-6"
>
<h3 id="open-roles" className="text-heading-h4 text-primary">
Busiest open roles
</h3>
<ul className="grid divide-y divide-subtle">
{ROLES.map((role) => (
<li
key={role.title}
className="flex flex-wrap items-center justify-between gap-2 py-3"
>
<div className="grid min-w-0">
<a
href="#open-role"
className="text-body-strong text-primary underline underline-offset-4"
>
{role.title}
</a>
<span className="text-body-small text-muted">
{role.team} · {role.applicants} applicants
</span>
</div>
<Badge label={role.stage} tone={role.tone} />
</li>
))}
</ul>
</section>
</div>
</div>
</div>
);
}
More dashboards and analytics blocks
- KPI overviewFour headline metrics with trend and change.
- Sales dashboardRevenue over time against target.
- People analyticsHeadcount by team, type and tenure.
- Engagement survey resultseNPS score and check-in patterns across the week.
- Budget varianceHow the budget moved from plan to actual.
- Skills comparisonOne person against the team average.
- Live status boardReal-time counts with tiny trends.
- Chart statesLoading, empty and error versions of any chart.