Payslip, September 2026
Paid 25 September 2026 · Pay period 1–30 September
Ayesha KhanSenior product designer · Employee ID NW-0142
Net pay£5,035.15
- Gross pay to date
- £47,260.50
- Tax paid to date
- £12,988.20
- Paid into
- Bank account ••••6610
payslip.tsx
import { LuDownload, LuMinus, LuPlus } from "react-icons/lu";
import { Accordion, AccordionItem, Avatar, Badge, Button } from "@nexera-ui/react";
// Sample data
interface Person {
id: string;
name: string;
initials: string;
role: string;
team: string;
email: string;
location: string;
status: "Active" | "On leave" | "Remote" | "Invited";
}
const PEOPLE: Person[] = [
{
id: "p1",
name: "Ayesha Khan",
initials: "AK",
role: "Senior product designer",
team: "Design",
email: "ayesha.khan@northwind.io",
location: "London",
status: "Active",
},
{
id: "p2",
name: "Sara Malik",
initials: "SM",
role: "Payroll specialist",
team: "People Ops",
email: "sara.malik@northwind.io",
location: "Lisbon",
status: "On leave",
},
{
id: "p3",
name: "Ahmed Raza",
initials: "AR",
role: "Engineering manager",
team: "Engineering",
email: "ahmed.raza@northwind.io",
location: "Lahore",
status: "Remote",
},
{
id: "p4",
name: "Mia Jensen",
initials: "MJ",
role: "Product manager",
team: "Product",
email: "mia.jensen@northwind.io",
location: "Copenhagen",
status: "Active",
},
{
id: "p5",
name: "Luis Ortega",
initials: "LO",
role: "Frontend engineer",
team: "Engineering",
email: "luis.ortega@northwind.io",
location: "Madrid",
status: "Active",
},
{
id: "p6",
name: "Yuki Tanaka",
initials: "YT",
role: "Recruiter",
team: "People Ops",
email: "yuki.tanaka@northwind.io",
location: "Tokyo",
status: "Active",
},
{
id: "p7",
name: "Chloe Martin",
initials: "CM",
role: "Data analyst",
team: "Finance",
email: "chloe.martin@northwind.io",
location: "Paris",
status: "Remote",
},
{
id: "p8",
name: "Omar Haddad",
initials: "OH",
role: "Support lead",
team: "Customer",
email: "omar.haddad@northwind.io",
location: "Dubai",
status: "Invited",
},
];
const money = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" });
const employee = PEOPLE[0];
const EARNINGS = [
{ label: "Basic salary", note: "£78,000 a year", amount: 6500 },
{ label: "Overtime", note: "6 hours at £56.25", amount: 337.5 },
{ label: "Remote working allowance", note: "Monthly", amount: 45 },
{ label: "Q3 performance bonus", note: "One-off", amount: 1200 },
] as const;
const DEDUCTIONS = [
{ label: "Income tax (PAYE)", note: "Tax code 1257L", amount: 2154.6 },
{ label: "National Insurance", note: "Category A", amount: 428.37 },
{ label: "Pension", note: "5% of qualifying earnings", amount: 401.88 },
{ label: "Cycle to work scheme", note: "Month 4 of 12", amount: 62.5 },
] as const;
const sum = (rows: readonly { amount: number }[]) =>
rows.reduce((total, row) => total + row.amount, 0);
const GROSS = sum(EARNINGS);
const DEDUCTED = sum(DEDUCTIONS);
function Rows({
rows,
total,
totalLabel,
}: {
rows: readonly { label: string; note: string; amount: number }[];
total: number;
totalLabel: string;
}) {
return (
<dl className="grid gap-3">
{rows.map((row) => (
<div key={row.label} className="flex items-start justify-between gap-4">
<dt className="grid">
<span className="text-body-default text-primary">{row.label}</span>
<span className="text-body-caption text-muted">{row.note}</span>
</dt>
<dd className="text-body-default text-primary tabular-nums">
{money.format(row.amount)}
</dd>
</div>
))}
<div className="flex justify-between gap-4 border-t border-subtle pt-3">
<dt className="text-body-strong text-primary">{totalLabel}</dt>
<dd className="text-body-strong text-primary tabular-nums">{money.format(total)}</dd>
</div>
</dl>
);
}
/** Payslip: earnings and deductions for one pay period, with the net pay. */
export default function Payslip() {
if (!employee) return null;
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<article
aria-labelledby="payslip-title"
className="mx-auto grid w-full max-w-2xl gap-5 rounded-xl border border-default bg-surface p-5 shadow-xs @3xl:p-6"
>
<header className="flex flex-wrap items-start justify-between gap-4">
<div className="grid gap-1">
<h2 id="payslip-title" className="text-heading-h3 text-primary">
Payslip, September 2026
</h2>
<p className="text-body-small text-secondary">
Paid 25 September 2026 · Pay period 1–30 September
</p>
</div>
<Badge tone="success" label="Paid" />
</header>
<div className="flex flex-wrap items-center gap-3 rounded-lg bg-sunken p-4">
<Avatar size="lg" initials={employee.initials} isDecorative />
<div className="grid min-w-0 flex-1">
<span className="text-body-strong text-primary">{employee.name}</span>
<span className="text-body-small text-secondary">
{employee.role} · Employee ID NW-0142
</span>
</div>
<div className="grid @sm:text-end">
<span className="text-body-caption text-muted">Net pay</span>
<span className="text-heading-h3 text-primary tabular-nums">
{money.format(GROSS - DEDUCTED)}
</span>
</div>
</div>
<Accordion variant="card" allowsMultipleExpanded defaultExpandedKeys={["earnings"]}>
<AccordionItem
id="earnings"
title="Earnings"
icon={<LuPlus />}
meta={money.format(GROSS)}
level={3}
>
<Rows rows={EARNINGS} total={GROSS} totalLabel="Gross pay" />
</AccordionItem>
<AccordionItem
id="deductions"
title="Deductions"
icon={<LuMinus />}
meta={money.format(DEDUCTED)}
level={3}
>
<Rows rows={DEDUCTIONS} total={DEDUCTED} totalLabel="Total deductions" />
</AccordionItem>
</Accordion>
<dl className="grid gap-2 rounded-lg border border-subtle p-4 text-body-small @3xl:grid-cols-3">
{[
["Gross pay to date", money.format(47260.5)],
["Tax paid to date", money.format(12988.2)],
["Paid into", "Bank account ••••6610"],
].map(([label, value]) => (
<div key={label} className="grid">
<dt className="text-muted">{label}</dt>
<dd className="text-body-strong text-primary tabular-nums">{value}</dd>
</div>
))}
</dl>
<div className="flex flex-wrap justify-end gap-2">
<a
href="#payslip-question"
className="self-center text-body-small text-brand-text underline underline-offset-4"
>
Question about this payslip?
</a>
<Button variant="secondary" leadingIcon={<LuDownload />}>
Download PDF
</Button>
</div>
</article>
</div>
);
}
More commerce and payments blocks
- Pricing plansMonthly or yearly plans with a recommended one.
- CheckoutCard details, billing address and order total.
- Saved payment methodsChoose, add or remove a card.
- Order summaryItems, discounts and totals.
- Product galleryPhotos with thumbnails and zoom.
- Reviews and ratingsAverage score, breakdown and written reviews.
- Order trackingWhere an order is, step by step.