The full toolkit from _shared/email-templates/components.ts — every component rendered live with its prop signature. All are pure functions returning HTML strings (no JSX, no framework); charts are table+div based (no inline SVG) so they survive Gmail and Outlook.
Eyebrow({ text })Tracked small-caps label above a hero heading.
| MEMBER · MARCUS |
Heading({ text, level?: 1|2|3, align? })Paragraph(text, variant?: primary|secondary|muted, { align?, size?: body|lead })Lead paragraph — 19px subhead used under a hero heading.
Body paragraph — the 16px workhorse for everything else in the message.
Button({ url, text, variant?: primary|secondary|success, gif? })Ink pill (primary), ghost (secondary), or an animated 300×168 GIF card via gif slug.
TextLink({ url, text })Card({ content, variant?: default|highlight|warning|success })SpecTable({ rows: [{ label, value }] })The signature key/value list of the Apple emails.
| Role | Staff Product Designer |
| Partner | Northwind Robotics |
| Club AI match | 94% |
InfoRow({ icon?, label, value })| When | Wed 2 Jul · 15:00 CET |
Divider({ spacing?: small|medium|large })Above.
Below.
Spacer(4|8|12|14|16|20|24|28|32|36|40|48|56|64)Vertical rhythm. A 24px gap shown between two rules.
StatusBadge({ status: confirmed|pending|cancelled|reminder|new, text? })|
CONFIRMED
|
|
PENDING
|
|
CANCELLED
|
AlertBox({ type: info|warning|success|error, title?, message })|
Heads up
A colored left keyline carries the state — no candy fill.
|
CodeBox({ code, label? })Avatar({ name, src?, size? })Image, or monogram on a light disc (image-block safe).
MW |
JourneyStepper({ steps, current, tone?: active|muted, loadingColor?: green|ink|null })| Applied | Reviewed | Interview | Decision |
| Applied | Reviewed | Closed |
RoleCard({ eyebrow?, title, pillText?, rows, rail?, ctaHtml?, matchPct?, stealth? })The flagship hero card — eyebrow + title + match pill + spec + optional rail/CTA.
| ||||||||
| ||||||||
| ||||||||
| View in pipeline |
WhyList({ title?, items })Your move |
✓ |
Call the partner today. |
✓ |
Capture the real reason while it’s fresh. |
✓ |
Re-open the backfill from the shortlist. |
QuoteCard({ name, quote, role?, avatarUrl? })
|
MetricStat({ value, label, delta?, tone?: positive|negative|neutral, sublabel? })MetricGrid({ metrics: MetricStat[], columns?: 2|3 })14
Candidates
▲ +2
| 6
Partners
| 2
Offers out
▲ +1
|
BarRow({ label, value, max, valueLabel?, fill?: ink|success|warning|error|muted })| Interviewing | 11 | |
BarChart({ title?, rows: [{ label, value, valueLabel?, fill? }], max? })| Applied | 41 | |
| Screened | 22 | |
| Interviewing | 11 | |
| Offer | 2 | |
| Placed | 3 | |
Sparkline({ values, height?, fill?, caption? })VideoCallCard({ platform, platformName, joinUrl, meetingId?, password?, dialIn?, instructions? })AttendeeList({ attendees: [{ name, email?, isOrganizer?, status? }], maxShow? })|
A
|
Alex Rivera (Organizer)
|
Accepted |
|
M
|
Marcus Webb
|
Pending |
MeetingPrepCard({ meetingType?: interview|general|intro, companyName?, interviewerName?, prepGuideUrl? })|
Prepare for Your Interview
|
CalendarButtons({ title, startDate, endDate, description?, location? })SchemaEvent({ name, startDate, endDate, location?, description?, organizerName?, organizerEmail?, attendees? })Non-visual — emits schema.org JSON-LD for calendar-aware clients. Source shown.
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Event",
"name": "Interview — Northwind",
"startDate": "2026-07-02T13:00:00.000Z",
"endDate": "2026-07-02T13:45:00.000Z",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
"location": {
"@type": "VirtualLocation",
"url": "https://meet.thequantumclub.com/x"
},
"organizer": {
"@type": "Organization",
"name": "The Quantum Club",
"url": "https://thequantumclub.com"
}
}
</script>