home / skills / openclaw / skills / orderly-ui-components

orderly-ui-components skill

/skills/tarnadas/orderly-ui-components

This skill helps you rapidly build trading UIs using pre-built Orderly components, boosting speed and consistency across dashboards.

npx playbooks add skill openclaw/skills --skill orderly-ui-components

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
12.2 KB
---
name: orderly-ui-components
description: Build trading interfaces using pre-built React components - OrderEntry, Positions, TradingPage, WalletConnect, Sheets, Tables
---

# 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

```bash
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:

```typescript
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

```typescript
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

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

---

## Positions Component

### Basic Positions Table

```typescript
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

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

---

## Orderbook Component

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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:

```css
/* 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

Overview

This skill provides a set of pre-built React UI components for building trading interfaces using Orderly Network components such as OrderEntry, Positions, Orderbook, WalletConnect, Charts, Tables, Sheets, and Modals. It bundles integration patterns, provider setup, and examples to rapidly assemble a production-grade trading page. The components are styled with Tailwind CSS and are designed to work with Orderly hooks and providers.

How this skill works

Wrap your React app with the required providers (OrderlyAppProvider, SymbolProvider, TradingPageProvider, QueryClientProvider) to supply network, symbol, and data context. Use component-specific providers where needed (OrderEntryProvider, OrderbookProvider) and import UI components to render order entry forms, orderbooks, charts, positions tables, and wallet connectors. Hooks and callback props handle submission, navigation, and toast notifications while components expose className and prop hooks for customization.

When to use it

  • When you need a production-ready trading UI quickly without building primitives from scratch.
  • When you want consistent, styled components that follow common trading UX patterns.
  • When you already use React 18+ and Tailwind CSS in your app.
  • When you need real-time orderbook, positions, and chart integration with wallet connect.
  • When you want modular components that plug into Orderly hooks and providers.

Best practices

  • Wrap the app root with QueryClientProvider and OrderlyAppProvider before any Orderly components.
  • Place SymbolProvider above symbol-dependent components and use component-specific providers for isolated state.
  • Keep Tailwind configured and use className or higher-specificity CSS to override styles safely.
  • Call hooks only inside provider-wrapped components to ensure data and websocket connectivity.
  • Use toast notifications and modals to surface order results and errors to users.

Example use cases

  • A single-page trading dashboard with Orderbook, TradingView chart, OrderEntry, and Positions panel.
  • Embedding an OrderEntry widget into a dashboard to enable quick limit/market orders.
  • A mobile-friendly trading layout that uses Sheet (drawer) for order details and modals for confirmations.
  • A reporting page using Table components to render trade history or aggregated position data.
  • A header component that includes WalletConnect or a custom wallet button showing connected address.

FAQ

What providers are required to use the components?

Wrap your app with QueryClientProvider and OrderlyAppProvider, and include SymbolProvider and TradingPageProvider. Use per-component providers like OrderEntryProvider or OrderbookProvider where required.

Do components require Tailwind CSS?

Components use Tailwind utility classes by default. Tailwind is recommended for styling but you can override styles via className or custom CSS.