SolanaUISolanaUI

Action Box

A generic single-input action form for staking, lending, depositing, bridging, and more

Stake
24.58
APY7.2%
Annual Rewards~1.77 SOL
ValidatorHelius
import { ActionBox } from "@/components/sol/action-box";

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

export function ActionBoxDemo() {
  return (
    <ActionBox
      tokens={[
        { icon: SOL_ICON, symbol: "SOL" },
        { icon: USDC_ICON, symbol: "USDC" },
      ]}
      defaultToken="SOL"
      balance="24.58"
      label="Stake"
      details={[
        { label: "APY", value: "7.2%", className: "text-emerald-500" },
        { label: "Annual Rewards", value: "~1.77 SOL" },
        { label: "Validator", value: "Helius" },
      ]}
      submitLabel="Stake SOL"
    />
  );
}

Installation

pnpm dlx shadcn@latest add @solanaui/action-box
npx shadcn@latest add @solanaui/action-box
yarn dlx shadcn@latest add @solanaui/action-box

Usage

Staking

<ActionBox
  tokens={[{ icon: SOL_ICON, symbol: "SOL" }]}
  defaultToken="SOL"
  balance="24.58"
  label="Stake"
  details={[
    { label: "APY", value: "7.2%", className: "text-emerald-500" },
    { label: "Annual Rewards", value: "~1.77 SOL" },
  ]}
  submitLabel="Stake SOL"
/>

Lending Supply

<ActionBox
  tokens={[{ icon: USDC_ICON, symbol: "USDC" }]}
  defaultToken="USDC"
  balance="1,250.00"
  label="Supply"
  details={[
    { label: "Supply APY", value: "8.45%" },
    { label: "Utilization", value: "78.4%" },
  ]}
  submitLabel="Supply USDC"
/>

Bridge

<ActionBox
  tokens={[{ icon: SOL_ICON, symbol: "SOL" }]}
  defaultToken="SOL"
  balance="24.58"
  label="Bridge"
  details={[
    { label: "Destination", value: "Ethereum" },
    { label: "Fee", value: "0.001 SOL" },
    { label: "Est. Time", value: "~15 min" },
  ]}
  submitLabel="Bridge SOL"
/>

Source Code

import { TokenInput } from "@/registry/sol/token-input";import { Button } from "@/components/ui/button";import { Separator } from "@/components/ui/separator";import type { DetailRow } from "@/registry/lib/types";import { cn } from "@/lib/utils";type ActionBoxDetail = DetailRow;interface ActionBoxProps {  tokens: { icon: string; symbol: string }[];  defaultToken?: string;  balance?: string;  label?: string;  details?: ActionBoxDetail[];  submitLabel?: string;  onSubmit?: () => void;  className?: string;}const ActionBox = ({  tokens,  defaultToken,  balance,  label,  details,  submitLabel = "Submit",  onSubmit,  className,}: ActionBoxProps) => {  return (    <div className={cn("flex flex-col gap-4 border rounded-lg p-4", className)}>      {label && (        <span className="text-sm font-medium text-muted-foreground">          {label}        </span>      )}      <TokenInput        tokens={tokens}        defaultToken={defaultToken}        balance={balance}      />      {details && details.length > 0 && (        <>          <Separator />          <div className="flex flex-col gap-1.5 text-sm">            {details.map((detail) => (              <div key={detail.label} className="flex justify-between">                <span className="text-muted-foreground">{detail.label}</span>                <span className={detail.className}>{detail.value}</span>              </div>            ))}          </div>        </>      )}      <Button className="w-full" size="lg" onClick={onSubmit}>        {submitLabel}      </Button>    </div>  );};export type { ActionBoxProps, ActionBoxDetail };export { ActionBox };