skills/orderlynetwork/skills/orderly-ui-components

orderly-ui-components

SKILL.md

Orderly Network: UI Components

This skill covers building trading interfaces using Orderly's pre-built React components from @orderly.network/react.

When to Use

  • Rapidly building a trading UI
  • Using pre-built, styled components
  • Implementing standard trading interface patterns

Prerequisites

  • React 18+
  • @orderly.network/react installed
  • Tailwind CSS (recommended for styling)

Installation

npm install @orderly.network/react @orderly.network/hooks @orderly.network/types

# Or with yarn
yarn add @orderly.network/react @orderly.network/hooks @orderly.network/types

Core Providers

Wrap your app with the required providers:

import {
  OrderlyAppProvider,
  TradingPageProvider,
  SymbolProvider,
  WalletConnector
} from '@orderly.network/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <OrderlyAppProvider
        brokerId="woofi_dex"
        chainFilter={[42161, 421614]}
      >
        <SymbolProvider>
          <TradingPageProvider>
            <Layout>
              <WalletConnector />
              <TradingPage />
            </Layout>
          </TradingPageProvider>
        </SymbolProvider>
      </OrderlyAppProvider>
    </QueryClientProvider>
  );
}

Order Entry Component

Basic Order Entry

import { OrderEntry, OrderEntryProvider } from '@orderly.network/ui-order-entry';
import { useOrderEntry } from '@orderly.network/hooks';

function OrderEntryContainer() {
  const { onSubmit } = useOrderEntry();

  const handleSubmit = async (params: any) => {
    try {
      await onSubmit(params);
      console.log('Order submitted');
    } catch (e) {
      console.error('Order failed', e);
    }
  };

  return (
    <div className="bg-gray-900 rounded-lg p-4 border border-gray-800">
      <OrderEntry
        onSubmit={handleSubmit}
        defaultTab="limit"
        hideMarket={false}
      />
    </div>
  );
}

export function OrderEntryWidget() {
  return (
    <OrderEntryProvider symbol="PERP_BTC_USDC">
      <OrderEntryContainer />
    </OrderEntryProvider>
  );
}

Order Entry Props

interface OrderEntryProps {
  onSubmit?: (params: OrderParams) => Promise<void>;
  defaultTab?: 'limit' | 'market';
  hideMarket?: boolean;
  hideLimit?: boolean;
  showLeverage?: boolean;
  className?: string;
}

Positions Component

Basic Positions Table

import { Positions } from '@orderly.network/ui-positions';

export function PositionsWidget() {
  const handleSymbolClick = (symbol: string) => {
    console.log('Navigate to:', symbol);
  };

  return (
    <div className="w-full">
      <Positions
        filter={{ symbol: 'PERP_ETH_USDC' }}  // Optional filter
        onSymbolClick={handleSymbolClick}
        showPagination={true}
      />
    </div>
  );
}

Positions Props

interface PositionsProps {
  filter?: {
    symbol?: string;
    side?: 'BUY' | 'SELL';
  };
  onSymbolClick?: (symbol: string) => void;
  showPagination?: boolean;
  pageSize?: number;
  className?: string;
}

Orderbook Component

import { Orderbook, OrderbookProvider } from '@orderly.network/ui-orderbook';

export function OrderbookWidget({ symbol }: { symbol: string }) {
  return (
    <OrderbookProvider symbol={symbol}>
      <Orderbook
        level={10}           // Number of levels to show
        showTotal={true}     // Show total column
        onItemClick={(price, side) => {
          console.log('Price clicked:', price, side);
        }}
      />
    </OrderbookProvider>
  );
}

Wallet Connect Component

Basic Wallet Connect

import { WalletConnect } from '@orderly.network/react';

export function Header() {
  return (
    <header className="flex justify-between items-center p-4">
      <div className="logo">My DEX</div>
      <WalletConnect />
    </header>
  );
}

Custom Wallet Button

import { useAccount, useWalletConnector } from '@orderly.network/hooks';

export function CustomWalletButton() {
  const { account, state } = useAccount();
  const wallet = useWalletConnector();

  if (state.status !== 'connected') {
    return (
      <button
        onClick={() => wallet.connect()}
        className="btn-primary"
      >
        Connect Wallet
      </button>
    );
  }

  return (
    <div className="wallet-menu">
      <span>{account.address?.slice(0, 6)}...{account.address?.slice(-4)}</span>
      <button onClick={() => wallet.disconnect()}>
        Disconnect
      </button>
    </div>
  );
}

Chart Components

TradingView Widget

import { TradingView } from '@orderly.network/ui-chart';

export function ChartWidget({ symbol }: { symbol: string }) {
  return (
    <div className="h-[500px]">
      <TradingView
        symbol={symbol}
        interval="1h"
        theme="dark"
        autosize={true}
      />
    </div>
  );
}

Lightweight Charts

import { LightweightChart } from '@orderly.network/ui-chart';

export function SimpleChart({ symbol }: { symbol: string }) {
  return (
    <div className="h-[400px]">
      <LightweightChart
        symbol={symbol}
        interval="15m"
        chartType="candlestick"
      />
    </div>
  );
}

Data Table Component

Generic Table

import { Table } from '@orderly.network/ui';

type TradeRow = {
  id: string;
  price: number;
  size: number;
  time: string;
  side: 'BUY' | 'SELL';
};

export function TradesTable({ data }: { data: TradeRow[] }) {
  return (
    <Table<TradeRow>
      dataSource={data}
      columns={[
        {
          title: 'Price',
          dataIndex: 'price',
          render: (value, record) => (
            <span className={record.side === 'BUY' ? 'text-green-500' : 'text-red-500'}>
              {value.toFixed(2)}
            </span>
          ),
        },
        {
          title: 'Size',
          dataIndex: 'size',
          render: (value) => value.toFixed(4),
        },
        {
          title: 'Time',
          dataIndex: 'time',
        },
      ]}
      rowKey="id"
      pagination={{ pageSize: 20 }}
    />
  );
}

Sheet (Drawer) Component

import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetFooter } from '@orderly.network/ui';

export function OrderDetailsSheet({ order }: { order: Order }) {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <button className="btn-secondary">View Details</button>
      </SheetTrigger>
      <SheetContent side="right">
        <SheetHeader>
          <h2>Order Details</h2>
        </SheetHeader>
        <div className="py-4">
          <div className="grid grid-cols-2 gap-2">
            <span>Symbol:</span>
            <span>{order.symbol}</span>
            <span>Side:</span>
            <span>{order.side}</span>
            <span>Price:</span>
            <span>{order.price}</span>
            <span>Quantity:</span>
            <span>{order.order_qty}</span>
            <span>Status:</span>
            <span>{order.status}</span>
          </div>
        </div>
        <SheetFooter>
          <button className="btn-primary">Close Position</button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}

Modal Component

import { Modal, ModalTrigger, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@orderly.network/ui';

export function ConfirmOrderModal({ order, onConfirm }: { order: Order; onConfirm: () => void }) {
  return (
    <Modal>
      <ModalTrigger asChild>
        <button className="btn-primary">Place Order</button>
      </ModalTrigger>
      <ModalContent>
        <ModalHeader>
          <h2>Confirm Order</h2>
        </ModalHeader>
        <ModalBody>
          <p>Are you sure you want to place this order?</p>
          <div className="order-summary">
            <p>{order.side} {order.quantity} {order.symbol} @ {order.price}</p>
          </div>
        </ModalBody>
        <ModalFooter>
          <button className="btn-secondary">Cancel</button>
          <button className="btn-primary" onClick={onConfirm}>Confirm</button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
}

Empty State Component

import { NoData } from '@orderly.network/ui';

export function EmptyOrders() {
  return (
    <div className="flex flex-col items-center justify-center py-12">
      <NoData width={200} height={200} className="text-gray-500" />
      <p className="mt-4 text-gray-400">No open orders</p>
      <button className="mt-2 btn-secondary">Place Order</button>
    </div>
  );
}

Notification/Toast Component

import { Toast, ToastProvider, useToast } from '@orderly.network/ui';

function TradingPage() {
  const { toast } = useToast();

  const handleOrderSubmit = async () => {
    try {
      await submitOrder();
      toast({
        title: 'Order Placed',
        description: 'Your order has been submitted successfully',
        variant: 'success',
      });
    } catch (error) {
      toast({
        title: 'Order Failed',
        description: error.message,
        variant: 'error',
      });
    }
  };

  return <button onClick={handleOrderSubmit}>Place Order</button>;
}

// In your app root
function App() {
  return (
    <ToastProvider>
      <TradingPage />
    </ToastProvider>
  );
}

Complete Trading Page Example

import {
  OrderlyAppProvider,
  TradingPageProvider,
  SymbolProvider,
  WalletConnect,
} from '@orderly.network/react';
import { OrderEntry, OrderEntryProvider } from '@orderly.network/ui-order-entry';
import { Positions } from '@orderly.network/ui-positions';
import { Orderbook, OrderbookProvider } from '@orderly.network/ui-orderbook';
import { TradingView } from '@orderly.network/ui-chart';
import { useOrderEntry } from '@orderly.network/hooks';

function TradingPage() {
  const symbol = 'PERP_BTC_USDC';

  return (
    <div className="trading-layout">
      {/* Header */}
      <header className="flex justify-between items-center p-4 border-b">
        <h1>My DEX</h1>
        <WalletConnect />
      </header>

      {/* Main Content */}
      <div className="grid grid-cols-12 gap-4 p-4">
        {/* Left: Orderbook */}
        <div className="col-span-2">
          <OrderbookProvider symbol={symbol}>
            <Orderbook level={15} />
          </OrderbookProvider>
        </div>

        {/* Center: Chart + Order Entry */}
        <div className="col-span-7">
          <div className="h-[500px] mb-4">
            <TradingView symbol={symbol} />
          </div>
          <OrderEntryProvider symbol={symbol}>
            <OrderEntry defaultTab="limit" />
          </OrderEntryProvider>
        </div>

        {/* Right: Positions */}
        <div className="col-span-3">
          <Positions showPagination={false} />
        </div>
      </div>
    </div>
  );
}

export function App() {
  return (
    <OrderlyAppProvider brokerId="woofi_dex">
      <SymbolProvider>
        <TradingPageProvider>
          <TradingPage />
        </TradingPageProvider>
      </SymbolProvider>
    </OrderlyAppProvider>
  );
}

Styling

Orderly components use Tailwind CSS classes. Customize with:

/* Override component styles */
.order-entry-root {
  /* Your styles */
}

.positions-table {
  /* Your styles */
}

/* Use Tailwind dark mode */
.dark .order-entry-root {
  /* Dark mode styles */
}

Common Issues

Components not rendering

  • Ensure all providers are wrapped correctly
  • Check that SymbolProvider is above symbol-dependent components
  • Verify Tailwind CSS is configured

Styling conflicts

  • Components use Tailwind utility classes
  • Override with higher-specificity CSS
  • Use className prop when available

Data not updating

  • Check WebSocket connection status
  • Verify account is connected
  • Ensure hooks are called inside provider components

Related Skills

  • orderly-sdk-react-hooks - Hook reference
  • orderly-trading-orders - Order management
  • orderly-websocket-streaming - Real-time data
Weekly Installs
17
GitHub Stars
2
First Seen
10 days ago
Installed on
opencode17
gemini-cli17
codebuddy17
github-copilot17
codex17
kimi-cli17