Today
Easy application
We just need a few final business details. You'll receive an offer based on your risk profile and transaction volume, and once you sign with our partner Liberis, your funding is already on its way to you.
5–8 business days
Funds received
Use your cash advance to fuel your next stage of growth, and pay it automatically through a fixed percentage of your daily sales.
Overview
The timeline lives in @flatpay-dk/ui as a single component that takes an items array. Each item carries an optional caption, a required title, an optional description, and a status — current, upcoming, or complete. The component renders a continuous rail behind a stack of nodes; it doesn't care whether the data comes from a static config (Capital flow) or a live feed (order state).
When the relationship is the content
Reach for Timeline when the order between items matters and the user benefits from seeing the chain. Static lists, checklists, or a flat set of cards are better served by List or Section.
States
Three node states cover every flow we've modelled. Set them per-item via status, or pass activeIndex on the timeline and the rail will derive each item's state from its position.
Today
Easy application
Verify your business details — funding follows.
status — current
The active step. Light-blue node + deep-teal dot mark it as the user's place in the flow.
5–8 business days
Funds received
Cash advance is on its way once the application is signed.
status — upcoming
A step ahead of the user. Muted node + grey dot — visible but not pulling attention.
9 May
Application signed
Funding agreement countersigned by Liberis.
status — complete
A step the user has already cleared. Charcoal node + a check glyph — same vocabulary the rest of the system uses for done states.
9 May, 11:24
Order placed
We've received your order and queued it for fulfilment.
9 May, 14:02
Packed
Two terminals + a receipt printer are in the shipper's queue.
10 May, 08:30
Shipped
Tracking: PostNL 3SABCD123456789. ETA tomorrow.
Estimated
Delivered
Hand-off to whoever signs at the merchant address.
activeIndex shorthand
When you don't want to set per-item status, pass `activeIndex` and the rail derives complete / current / upcoming from position.
Numbered nodes
When the timeline is also a numbered process — onboarding, a checklist with strict order — pass node on each item to render its index instead of the default dot. The wrapper still paints the surface, so colour stays in step with status.
Step 1
Connect your bank
Link the account where your daily payouts will land.
Step 2
Verify your business
Upload an ID document and confirm your Chamber of Commerce number.
Step 3
Sign your contract
Final paperwork before funding is released.
Responsive
The timeline doesn't change shape on mobile — it's already a column. What changes is type and node sizing: title drops from 24 px → 20 px, node from 48 px → 40 px, gap from 24 px → 16 px. The rail stays continuous; the data the user reads stays the same.
Anatomy
Two columns. The rail handles wayfinding; the text column carries the content.
| Part | Role |
|---|---|
| Rail | 1 px line in `border-border` running behind a stack of 48 px (40 px on mobile) circular nodes. The line stops at the centre of the last node so it doesn't trail off into empty space. |
| Node | Carries the status surface. `current` = light blue with a deep teal dot; `upcoming` = muted neutral with a quiet inner dot; `complete` = filled charcoal with a check glyph. Override the centre via `node` for numbered steps. |
| Caption | Inter Tight Medium 14 px / muted-foreground. The eyebrow that anchors the step in time — a duration ('5–8 business days'), a date, or a milestone label like 'Today'. |
| Title | Inter Tight Bold 24 px / 20 px on mobile. The single most prominent thing in the row. |
| Description | Inter Tight Regular 16 px / muted-foreground. Capped at 65ch via `max-width` so long body text wraps before fatigue. |
Accessibility
The component renders an ordered list (<ol>) so screen readers announce the sequence and the position of each item. Nodes and the rail line are decorative — they're marked aria-hidden so the assistive-tech outline stays focused on the meaningful content. The status palette is reinforced by copy (the caption tells the user when the step happens) so meaning never lives only in colour.
Code
Capital flow (the canonical case)
tsx
import { Timeline } from "@flatpay-dk/ui";
<Timeline
items={[
{
caption: "Today",
title: "Easy application",
description:
"We just need a few final business details. You'll receive an offer based on your risk profile and transaction volume.",
status: "current",
},
{
caption: "5–8 business days",
title: "Funds received",
description:
"Use your cash advance to fuel your next stage of growth.",
status: "upcoming",
},
]}
/>;Order tracking (with `activeIndex`)
tsx
<Timeline
activeIndex={2}
items={[
{ caption: "9 May, 11:24", title: "Order placed" },
{ caption: "9 May, 14:02", title: "Packed" },
{ caption: "10 May, 08:30", title: "Shipped" },
{ caption: "Estimated", title: "Delivered" },
]}
/>;Numbered onboarding
tsx
<Timeline
items={[
{ title: "Connect your bank", status: "complete", node: <>1</> },
{ title: "Verify your business", status: "current", node: <>2</> },
{ title: "Sign your contract", status: "upcoming", node: <>3</> },
]}
/>;Best practices
Today
Easy application
Verify your details.
Do
Use the caption to anchor the step in time. 'Today', '5–8 business days', or a real date — give the user something they can plan around.
Easy application
Verify your details.
Don't
Don't ship a timeline without anchoring captions. The rail implies sequence; the captions tell the user what 'next' actually means.
Today
Easy application
Two pages of business details, then sign.
Do
Keep descriptions short. The timeline is a wayfinding surface — long copy here drowns the rail's signal.
Today
Easy application
We just need a few final business details. You'll receive an offer based on your risk profile and transaction volume, and once you sign with our partner Liberis, your funding is already on its way to you. The full underwriting process takes between 24 and 72 hours and we may reach out for clarification depending on your business type.
Don't
Don't paste an entire policy paragraph into a description. If the step needs that much explanation, it belongs on its own page.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items* | TimelineItem[] | — | The ordered set of milestones. |
| activeIndex | number | — | Convenience: items before this index render as `complete`, the one at the index as `current`, the rest as `upcoming`. Per-item `status` overrides this. |
| className | string | — | Forwarded to the wrapper <ol>. |
TimelineItem
| Prop | Type | Default | Description |
|---|---|---|---|
| title* | string | — | Headline. Set in 24 px bold (20 px on mobile). |
| caption | string | — | Eyebrow above the title — a date or duration. Drives wayfinding. |
| description | ReactNode | — | Body copy. Keep it to 1–3 sentences. |
| status | "current" | "upcoming" | "complete" | "upcoming" | Per-item visual state. Overrides the timeline's `activeIndex` derivation. |
| node | ReactNode | — | Custom node content (e.g. a step number or icon). The wrapper still applies the status surface; pass content that inherits via currentColor. |