Trade Box
A perps/margin trading form with long/short toggle, token input, leverage slider, and order details
4,812.50
5x
Est. Entry Price$162.56
Liquidation Price$132.45
Fees0.05%
import { TradeBox } from "@/components/sol/trade-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 TradeBoxDemo() {
return (
<TradeBox
tokens={[
{ icon: USDC_ICON, symbol: "USDC" },
{ icon: SOL_ICON, symbol: "SOL" },
]}
defaultToken="USDC"
balance="4,812.50"
details={[
{ label: "Est. Entry Price", value: "$162.56" },
{ label: "Liquidation Price", value: "$132.45", className: "text-red-400" },
{ label: "Fees", value: "0.05%" },
]}
/>
);
}Installation
pnpm dlx shadcn@latest add @solanaui/trade-box
npx shadcn@latest add @solanaui/trade-box
yarn dlx shadcn@latest add @solanaui/trade-box
Usage
TradeBox is purpose-built for perpetuals and margin trading. It always includes long/short toggle buttons and a leverage slider.
For non-trading actions like staking, lending, depositing, or bridging, use ActionBox instead.
<TradeBox
tokens={[{ icon: USDC_ICON, symbol: "USDC" }]}
defaultToken="USDC"
balance="4,812.50"
leverageMin={1}
leverageMax={50}
leverageDefault={5}
details={[
{ label: "Est. Entry Price", value: "$162.56" },
{ label: "Liquidation Price", value: "$132.45", className: "text-red-400" },
{ label: "Fees", value: "0.05%" },
]}
submitLabel="Open Long"
/>Custom Labels
<TradeBox
tokens={[{ icon: SOL_ICON, symbol: "SOL" }]}
defaultToken="SOL"
labels={["Buy", "Sell"]}
defaultSide="long"
leverageMax={20}
submitLabel="Place Order"
/>Submit Handler
Pass onSubmit to handle order execution when the button is clicked.
<TradeBox
tokens={[{ icon: SOL_ICON, symbol: "SOL" }]}
defaultToken="SOL"
onSubmit={() => {
// Execute trade logic
}}
/>Source Code
"use client";import { LeverageSlider } from "@/registry/sol/leverage-slider";import { TokenInput } from "@/registry/sol/token-input";import { TradeButtons } from "@/registry/sol/trade-buttons";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 TradeBoxDetail = DetailRow;interface TradeBoxProps { tokens: { icon: string; symbol: string }[]; defaultToken?: string; balance?: string; labels?: [string, string]; defaultSide?: string; leverageMin?: number; leverageMax?: number; leverageDefault?: number; leverageStep?: number; details?: TradeBoxDetail[]; submitLabel?: string; onSubmit?: () => void; className?: string;}const TradeBox = ({ tokens, defaultToken, balance, labels = ["Long", "Short"], defaultSide = "long", leverageMin = 1, leverageMax = 50, leverageDefault = 5, leverageStep = 1, details, submitLabel = "Open Long", onSubmit, className,}: TradeBoxProps) => { return ( <div className={cn("flex flex-col gap-4 border rounded-lg p-4", className)}> <TradeButtons defaultValue={defaultSide} labels={labels} /> <Separator /> <div className="flex flex-col gap-2"> <TokenInput tokens={tokens} defaultToken={defaultToken} balance={balance} /> </div> <LeverageSlider min={leverageMin} max={leverageMax} defaultValue={[leverageDefault]} step={leverageStep} /> {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 { TradeBoxProps, TradeBoxDetail };export { TradeBox };