Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Billing History Timeline Block for Svelte

Four invoices on a rail, each opening in place to its payment attempts, reminder emails and the day it was paid, with totals for invoiced, collected and still owed and a Retry payment button on the overdue one.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

See what happened to every invoice with this billing-history timeline for Svelte with Ark UI. It is written for Remitwell, a fictional invoice-collection service. A hairline frame with a plus mark on each corner holds a band of three figures (invoiced, collected and still owed), then four invoices on a rail, newest first. Each row gives the invoice number in monospace, the amount, Paid or Overdue in words and a derived summary: "Paid 6 days after the due date", or "Overdue 10 days, due 8 Oct" counted from 18 Oct. Pressing a row opens a small rail of the attempts made against it: a failed attempt with the card's reason, a reminder email, the next attempt and the day it was paid. On the overdue invoice, "Retry payment" queues a retry in this demo and says that no card was charged. It is built from Guides and Button with a native button per row and CSS for the rail. It is not the invoice table: it shows the collection process, not the list of documents. The invoices are example data.

FAQ

How do I change the invoices?

Edit INVOICES at the top of the file: an id, the amount in integer cents, the ISO due date and the steps, oldest first, each a kind ("paid", "failed" or "email"), a day and a line of text. The totals, the "days after the due date" and the overdue days are derived from them and from AS_OF.

How does it decide an invoice is paid?

An invoice is paid when one of its steps has the kind "paid". The days late are that step's date minus the due date; an open invoice counts its overdue days from the fixed AS_OF date, never from the clock, so the page reads the same on every load.

What stays in the page, and how do I make Retry real?

The open rows and the queued retry stay in the page; nothing is saved or sent and no card is charged. To wire it, call your billing API from queue(), add the new attempt to the invoice's steps when it answers, and keep the status line as the place where the result is spoken.

Is it accessible?

Each row is a real button with aria-expanded and aria-controls, the closed attempts are removed from the tab order, and Paid or Overdue is a word beside the node, never only its fill. Failed, email and paid steps each carry text as well as an icon. The foot is a polite status line.

How is money handled?

Amounts are integer cents, formatted by one helper with a thousands separator, and each price is kept left to right inside right-to-left text. The totals are sums of the cents, so they cannot drift from the rows.

How does it look on a phone?

The rows are the same, narrower: the amount stays at the end of the invoice line and the attempts stack under it with their dates at the end.