PParable
All components

Token Swap Card

Blocks & Slices

A demo-grade crypto swap card with two token fields (searchable keyboard-driven picker + amount input) whose amounts derive from the USD price ratio, a center button that flips 180° and swaps the sides on a spring, a live rate line, and a Swap button that runs an inline pending → done animation. The flip, card cross, and spinner drop to instant state swaps under prefers-reduced-motion.

Inspired by Skiper UI — Aave token swap (pattern) — independently built, not affiliated. Attribution policy

Swap

demo
ETH
$4,680.66
USDC
$4,680.66
Rate1 ETH3,120.44 USDC

Installation

npx shadcn@latest add https://parable-three.vercel.app/r/token-swap-card.json

Runs the shadcn CLI — the component source is copied intocomponents/parable/token-swap-card.tsx. You own it from there.

Usage

The exact code rendering the preview above.

<div className="w-full max-w-sm">
    <TokenSwapCard
      defaultFrom="ETH"
      defaultTo="USDC"
      defaultAmount="1.5"
      tokens={[
        { symbol: "ETH", name: "Ethereum", price: 3120.44, icon: <div className="size-full rounded-full bg-gradient-to-br from-indigo-400 to-violet-600" /> },
        { symbol: "USDC", name: "USD Coin", price: 1, icon: <div className="size-full rounded-full bg-gradient-to-br from-sky-400 to-blue-600" /> },
        { symbol: "SOL", name: "Solana", price: 176.9, icon: <div className="size-full rounded-full bg-gradient-to-br from-fuchsia-400 to-purple-600" /> },
        { symbol: "WBTC", name: "Wrapped Bitcoin", price: 68420, icon: <div className="size-full rounded-full bg-gradient-to-br from-amber-400 to-orange-500" /> },
        { symbol: "ARB", name: "Arbitrum", price: 0.82, icon: <div className="size-full rounded-full bg-gradient-to-br from-cyan-400 to-blue-500" /> },
      ]}
    />
  </div>

Props

TokenSwapCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSubmit">

PropTypeDefaultDescription
tokens*SwapToken[]Tokens offered on both sides. Needs at least two distinct symbols.
defaultFromstringSymbol pre-selected in the "You pay" field. Defaults to `tokens[0]`.
defaultTostringSymbol pre-selected in the "You receive" field. Defaults to `tokens[1]`.
defaultAmountstring"1"Amount pre-filled in the "You pay" field. Defaults to `"1"`.
onSwap(payload: TokenSwapPayload) => Promise<void> | voidRuns when "Swap" is pressed. Resolve to reach the done state, throw to fall back to idle. Defaults to a fake ~1.1s settle so the card demos itself.
accentstring"#8b5cf6"Accent hex — button, focus ring, active option. Default Parable violet.

npm dependencies

  • motion