SolanaUISolanaUI

Txn Table

A table for displaying blockchain transactions with signature links, action badges, and token info

SignatureTimeActionTokenAmount
5UfD...3kPm2 minutes agoSwap
SOL
SOL
24.5 SOL$3,982.72
8mRx...7jKn15 minutes agoTransfer
USDC
USDC
1,000 USDC$1,000.00
3vPq...9hLrabout 1 hour agoStake
JitoSOL
JitoSOL
100 SOL$16,256.00
import { TxnTable } from "@/components/sol/txn-table";

const SOL_ICON =
  "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png";

export function TxnTableDemo() {
  return (
    <TxnTable
      transactions={[
        {
          signature: "5UfD...3kPm",
          timestamp: new Date(Date.now() - 2 * 60 * 1000),
          action: "Swap",
          token: "SOL",
          tokenIcon: SOL_ICON,
          amount: "24.5 SOL",
          value: "$3,982.72",
        },
      ]}
    />
  );
}

Installation

pnpm dlx shadcn@latest add @solanaui/txn-table
npx shadcn@latest add @solanaui/txn-table
yarn dlx shadcn@latest add @solanaui/txn-table

Usage

<TxnTable
  transactions={[
    {
      signature: "5UfD...3kPm",
      timestamp: new Date(Date.now() - 2 * 60 * 1000),
      action: "Swap",
      token: "SOL",
      tokenIcon: SOL_ICON,
      amount: "24.5 SOL",
      value: "$3,982.72",
    },
  ]}
/>

Source Code

import { formatDistanceToNow } from "date-fns";import { ExternalLinkIcon } from "lucide-react";import { Badge } from "@/components/ui/badge";import {  Table,  TableBody,  TableCell,  TableHead,  TableHeader,  TableRow,} from "@/components/ui/table";import { cn } from "@/lib/utils";import { TokenIcon } from "@/registry/sol/token-icon";interface TxnTableProps {  transactions: {    signature: string;    timestamp: Date;    action: string;    token: string;    tokenIcon?: string;    amount: string;    value?: string;    explorerUrl?: string;  }[];  className?: string;}const truncateSignature = (sig: string) => {  if (sig.length <= 12) return sig;  return `${sig.slice(0, 4)}...${sig.slice(-4)}`;};const TxnTable = ({ transactions, className }: TxnTableProps) => {  return (    <Table className={className}>      <TableHeader>        <TableRow>          <TableHead>Signature</TableHead>          <TableHead>Time</TableHead>          <TableHead>Action</TableHead>          <TableHead>Token</TableHead>          <TableHead className="text-right">Amount</TableHead>        </TableRow>      </TableHeader>      <TableBody>        {transactions.map((txn, i) => {          const explorerUrl =            txn.explorerUrl ?? `https://solscan.io/tx/${txn.signature}`;          return (            <TableRow key={`${txn.signature}-${i}`}>              <TableCell>                <a                  href={explorerUrl}                  target="_blank"                  rel="noopener noreferrer"                  className={cn(                    "inline-flex items-center gap-1 font-mono text-xs",                    "text-muted-foreground hover:text-foreground transition-colors",                  )}                >                  {truncateSignature(txn.signature)}                  <ExternalLinkIcon className="size-3" />                </a>              </TableCell>              <TableCell className="text-muted-foreground text-sm">                {formatDistanceToNow(txn.timestamp, { addSuffix: true })}              </TableCell>              <TableCell>                <Badge variant="secondary" className="capitalize text-xs">                  {txn.action}                </Badge>              </TableCell>              <TableCell>                <div className="flex items-center gap-1.5">                  {txn.tokenIcon && (                    <TokenIcon                      src={txn.tokenIcon}                      alt={txn.token}                      width={18}                      height={18}                    />                  )}                  <span className="font-medium">{txn.token}</span>                </div>              </TableCell>              <TableCell className="text-right">                <div className="flex flex-col items-end">                  <span className="font-medium">{txn.amount}</span>                  {txn.value && (                    <span className="text-xs text-muted-foreground">                      {txn.value}                    </span>                  )}                </div>              </TableCell>            </TableRow>          );        })}      </TableBody>    </Table>  );};export type { TxnTableProps };export { TxnTable };