Skip to main content
The @repo/ui package provides a comprehensive React component library for building consistent user interfaces across the Exness Trading Platform.

Installation

This package is internal to the monorepo and installed automatically:
"dependencies": {
  "@repo/ui": "workspace:*"
}

Features

  • 50+ Components: Comprehensive UI component library
  • Radix UI: Built on unstyled, accessible components
  • Tailwind CSS: Utility-first styling with CSS variables
  • Dark Mode: Built-in theme support with next-themes
  • TypeScript: Full type safety and IntelliSense
  • Accessible: WCAG compliant components
  • Customizable: Style variants using class-variance-authority

Package Structure

The package exports components, utilities, and hooks through subpath exports:
import { Button } from '@repo/ui/components/button';
import { Card } from '@repo/ui/components/card';
import { cn } from '@repo/ui/lib/utils';
import { useIsMobile } from '@repo/ui/hooks/use-mobile';
import '@repo/ui/globals.css';

Available Components

Accordion

Collapsible content panels

Alert

Status messages and notifications

Alert Dialog

Modal confirmation dialogs

Avatar

User profile images

Badge

Status indicators and labels

Breadcrumb

Navigation breadcrumbs

Button

Interactive buttons

Button Group

Grouped button controls

Calendar

Date picker component

Card

Content containers

Carousel

Image/content carousel

Chart

Data visualization

Checkbox

Checkbox inputs

Collapsible

Expandable content

Command

Command palette

Context Menu

Right-click menus

Dialog

Modal dialogs

Drawer

Side panel drawers

Dropdown Menu

Dropdown menus

Empty

Empty state displays

Field

Form field wrapper

Form

Form components

Hover Card

Hoverable popovers

Input

Text input fields

Input Group

Grouped inputs

Input OTP

OTP input component
And 25+ more components including Labels, Menus, Modals, Popovers, Progress bars, Select dropdowns, Sliders, Tables, Tabs, Textareas, Toasts, Tooltips, and more!

Basic Usage

Button Component

import { Button } from '@repo/ui/components/button';

export function ButtonDemo() {
  return (
    <div className="flex gap-2">
      <Button variant="default">Default</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
    </div>
  );
}

Card Component

import { 
  Card, 
  CardHeader, 
  CardTitle, 
  CardDescription,
  CardContent,
  CardFooter,
  CardAction
} from '@repo/ui/components/card';
import { Button } from '@repo/ui/components/button';

export function TradingCard() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>BTC/USDT</CardTitle>
        <CardDescription>Bitcoin to US Dollar</CardDescription>
        <CardAction>
          <Button size="sm" variant="outline">Trade</Button>
        </CardAction>
      </CardHeader>
      <CardContent>
        <div className="text-3xl font-bold">$50,000.00</div>
        <div className="text-sm text-green-600">+2.5% (24h)</div>
      </CardContent>
      <CardFooter>
        <Button className="w-full">Place Order</Button>
      </CardFooter>
    </Card>
  );
}

Trading Platform Examples

Order Entry Form

import { Card, CardHeader, CardTitle, CardContent } from '@repo/ui/components/card';
import { Button } from '@repo/ui/components/button';
import { Input } from '@repo/ui/components/input';
import { Label } from '@repo/ui/components/label';
import { Select } from '@repo/ui/components/select';

export function OrderForm() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Place Order</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="space-y-2">
          <Label htmlFor="symbol">Trading Pair</Label>
          <Select>
            <option value="btc">BTC/USDT</option>
            <option value="eth">ETH/USDT</option>
            <option value="sol">SOL/USDT</option>
          </Select>
        </div>
        
        <div className="space-y-2">
          <Label htmlFor="quantity">Quantity</Label>
          <Input 
            id="quantity" 
            type="number" 
            placeholder="0.00" 
          />
        </div>
        
        <div className="space-y-2">
          <Label htmlFor="price">Price (USDT)</Label>
          <Input 
            id="price" 
            type="number" 
            placeholder="0.00" 
          />
        </div>
        
        <div className="grid grid-cols-2 gap-2">
          <Button variant="default" className="w-full">
            Buy
          </Button>
          <Button variant="destructive" className="w-full">
            Sell
          </Button>
        </div>
      </CardContent>
    </Card>
  );
}

Price Ticker

import { Badge } from '@repo/ui/components/badge';
import { Card, CardContent } from '@repo/ui/components/card';
import { ArrowUp, ArrowDown } from 'lucide-react';

interface PriceTickerProps {
  symbol: string;
  price: number;
  change: number;
}

export function PriceTicker({ symbol, price, change }: PriceTickerProps) {
  const isPositive = change >= 0;
  
  return (
    <Card>
      <CardContent className="flex items-center justify-between p-4">
        <div>
          <div className="text-sm text-muted-foreground">{symbol}</div>
          <div className="text-2xl font-bold">${price.toFixed(2)}</div>
        </div>
        <Badge 
          variant={isPositive ? "default" : "destructive"}
          className="flex items-center gap-1"
        >
          {isPositive ? <ArrowUp className="size-3" /> : <ArrowDown className="size-3" />}
          {Math.abs(change).toFixed(2)}%
        </Badge>
      </CardContent>
    </Card>
  );
}

Portfolio Overview

import { Card, CardHeader, CardTitle, CardContent } from '@repo/ui/components/card';
import { Progress } from '@repo/ui/components/progress';

interface Asset {
  symbol: string;
  percentage: number;
  value: number;
}

export function PortfolioOverview({ assets }: { assets: Asset[] }) {
  const total = assets.reduce((sum, asset) => sum + asset.value, 0);
  
  return (
    <Card>
      <CardHeader>
        <CardTitle>Portfolio Allocation</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        {assets.map((asset) => (
          <div key={asset.symbol} className="space-y-2">
            <div className="flex justify-between text-sm">
              <span>{asset.symbol}</span>
              <span className="font-medium">
                ${asset.value.toFixed(2)} ({asset.percentage.toFixed(1)}%)
              </span>
            </div>
            <Progress value={asset.percentage} />
          </div>
        ))}
        <div className="pt-4 border-t">
          <div className="flex justify-between font-bold">
            <span>Total</span>
            <span>${total.toFixed(2)}</span>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

Utilities

cn() - Class Name Utility

Combines class names with Tailwind merge:
import { cn } from '@repo/ui/lib/utils';

export function Component({ className }: { className?: string }) {
  return (
    <div 
      className={cn(
        'rounded-lg border p-4', // Base classes
        className // Override classes
      )}
    >
      Content
    </div>
  );
}

// Usage
<Component className="bg-blue-500 text-white" />

Hooks

useIsMobile

Detects if the viewport is mobile-sized:
import { useIsMobile } from '@repo/ui/hooks/use-mobile';
import { Button } from '@repo/ui/components/button';
import { Drawer } from '@repo/ui/components/drawer';
import { Dialog } from '@repo/ui/components/dialog';

export function ResponsiveModal({ children }: { children: React.ReactNode }) {
  const isMobile = useIsMobile();
  
  if (isMobile) {
    return <Drawer>{children}</Drawer>;
  }
  
  return <Dialog>{children}</Dialog>;
}

Styling

Import Global Styles

Import the global styles in your root layout:
// app/layout.tsx
import '@repo/ui/globals.css';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Theme Configuration

The package uses CSS variables for theming:
/* Customize in your app's globals.css */
:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  /* ... more variables */
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  /* ... dark mode variables */
}

Dark Mode

import { ThemeProvider } from 'next-themes';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      {children}
    </ThemeProvider>
  );
}

Component Variants

Many components use class-variance-authority for variants:
import { Button, buttonVariants } from '@repo/ui/components/button';
import Link from 'next/link';

// Use as component
<Button variant="outline" size="lg">Click me</Button>

// Use variants with other elements
<Link 
  href="/features/real-time-trading" 
  className={buttonVariants({ variant: "ghost" })}
>
  Trade
</Link>

Best Practices

Import only the components you need to optimize bundle size:
// Good
import { Button } from '@repo/ui/components/button';
import { Card } from '@repo/ui/components/card';

// Avoid
import * from '@repo/ui';
Always use the cn() utility for combining class names:
import { cn } from '@repo/ui/lib/utils';

<div className={cn('base-class', conditionalClass && 'active')} />
Build complex UIs by composing simple components:
<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>Content</CardContent>
</Card>
Combine components with hooks for responsive designs:
const isMobile = useIsMobile();
return isMobile ? <MobileView /> : <DesktopView />;

Customization

Extending Components

import { Button } from '@repo/ui/components/button';
import { cn } from '@repo/ui/lib/utils';

export function TradingButton({ 
  children, 
  className,
  ...props 
}: React.ComponentProps<typeof Button>) {
  return (
    <Button 
      className={cn('font-bold uppercase tracking-wide', className)}
      {...props}
    >
      {children}
    </Button>
  );
}

Creating Custom Variants

import { cva } from 'class-variance-authority';
import { cn } from '@repo/ui/lib/utils';

const tradingCardVariants = cva(
  'rounded-lg border p-4',
  {
    variants: {
      trend: {
        up: 'border-green-500 bg-green-50',
        down: 'border-red-500 bg-red-50',
        neutral: 'border-gray-300'
      }
    }
  }
);

export function TradingCard({ trend, className, children }) {
  return (
    <div className={cn(tradingCardVariants({ trend }), className)}>
      {children}
    </div>
  );
}

@repo/utils

Utility functions for use with UI components

@repo/types

Shared type definitions for component props

Build docs developers (and LLMs) love