Tx / activity history row — icon · title · time · status · amount.
Anatomy
┌──────────────────────────────────────────────┐ │ [◎] Swapped SOL → USDC +12.40 USDC │ │ 2m ago CONFIRMED │ │ icon title · time · status word amount │ └──────────────────────────────────────────────┘
Props
| Prop | Type | Default | Notes | ||
|---|---|---|---|---|---|
title | string | — | What happened. | ||
time | string | — | Preformatted ("2m ago"). | ||
status | "pending" | "confirmed" \ | "failed"` | — | Word + tint. |
amount | string | — | Preformatted with sign + unit. | ||
tokenSymbol | string | — | Drives TokenIcon; omit → diamond placeholder. | ||
tokenIconSrc | string | — | TokenIcon image. | ||
onClick | () => void | — | When set, row renders as a <button>. | ||
className | string | — | cn-merged. |
Server-safe (no "use client") unless the caller needs handlers — the
component itself has no client-only APIs.
Motion
Interactive only: duration-150 background + press scale. Status and
amount updates swap text in place — data surfaces never bounce.
A11y
Status is a visible word, not color alone. Interactive rows are real
<button>s with focus ring. Title truncates visually but remains in
the accessible name. Prefer pairing pending rows with a live-region
parent (or TxStatus) when the list itself streams.