← Back to blog

Designing Dark Mode for Trading Interfaces

Why trading UIs are almost universally dark, the science behind it, and a practical guide to building a token-based theming system that handles both modes.

By Oliver Benns


Open any professional trading terminal - Bloomberg, Refinitiv Eikon, Binance Pro, Thinkorswim - and you will see a dark interface. This is not a design trend. It is a functional decision rooted in how traders use screens.

This post explains why dark mode is the default for trading, and how to implement a theming system in React that handles it properly.

Why dark mode is the standard

Traders stare at screens for 8–14 hours a day. Often multiple screens simultaneously. Dark backgrounds reduce overall luminance, which reduces eye strain over extended sessions.

Beyond comfort, dark mode serves functional purposes in trading:

  • Data density - Trading interfaces are unusually dense. Dark backgrounds allow more visual elements (charts, grids, blotters) to coexist without competing for attention.
  • Colour signalling - Red and green indicators are more visually distinct against dark backgrounds. On white backgrounds, light green and light red can appear washed out.
  • Focus direction - Bright elements on a dark canvas naturally draw the eye. Critical data points (price changes, alerts, P&L) stand out without needing larger fonts or heavier weights.
  • Multi-monitor glare - In multi-screen setups, a bright white application creates glare that bleeds into adjacent screens.

The colour system

A trading interface needs more semantic colours than a typical application. Beyond the standard background, foreground, and accent tokens, you need:

:root { /* Positive/negative - the most critical semantic pair */ --color-positive: oklch(0.72 0.19 145); /* green */ --color-negative: oklch(0.63 0.21 25); /* red */ /* Surface hierarchy - at least 3 levels for nested panels */ --color-surface-0: oklch(0.15 0 0); /* deepest background */ --color-surface-1: oklch(0.20 0 0); /* card/panel */ --color-surface-2: oklch(0.25 0 0); /* elevated element */ /* Text hierarchy */ --color-text-primary: oklch(0.98 0 0); --color-text-secondary: oklch(0.70 0 0); --color-text-muted: oklch(0.50 0 0); /* Interactive states */ --color-hover: oklch(1 0 0 / 5%); --color-active: oklch(1 0 0 / 10%); --color-focus-ring: oklch(0.55 0 0); }

Using OKLCH ensures perceptually uniform colours. The green and red will appear equally vibrant, unlike HSL where matching saturation does not guarantee matching perceived intensity.

Surface hierarchy matters

Trading layouts use deeply nested panels - an order book inside a tab inside a split pane inside a workspace. Each nesting level needs a distinct surface colour to create visual separation without relying on borders.

A common approach is three surface levels:

LevelUseExample
Surface 0Page background, gaps between panelsWorkspace background
Surface 1Primary content panelsOrder book, chart container
Surface 2Elevated elements within panelsDropdown menus, tooltips, modals

Each step should increase lightness by roughly 4–6% in OKLCH. More than that and the contrast becomes distracting. Less and the hierarchy is invisible.

Implementing the theme in React

Use CSS custom properties as the source of truth and switch them at the root. This avoids prop-drilling theme values through the component tree.

// Theme configuration const themes = { dark: { "--color-surface-0": "oklch(0.15 0 0)", "--color-surface-1": "oklch(0.20 0 0)", "--color-surface-2": "oklch(0.25 0 0)", "--color-text-primary": "oklch(0.98 0 0)", "--color-positive": "oklch(0.72 0.19 145)", "--color-negative": "oklch(0.63 0.21 25)", }, light: { "--color-surface-0": "oklch(0.97 0 0)", "--color-surface-1": "oklch(1.00 0 0)", "--color-surface-2": "oklch(0.95 0 0)", "--color-text-primary": "oklch(0.15 0 0)", "--color-positive": "oklch(0.45 0.18 145)", "--color-negative": "oklch(0.50 0.22 25)", }, } as const;

Note that the green and red values change between modes. The dark mode uses lighter, more vibrant shades; the light mode uses darker, more saturated ones. This maintains consistent contrast ratios against their respective backgrounds.

Typography in dark mode

Light text on a dark background appears heavier than the same font weight on a light background - an optical illusion called irradiation. Compensate by:

  • Using font-weight: 400 instead of 500 for body text in dark mode
  • Reducing text opacity slightly for secondary text rather than using a lighter colour
  • Avoiding pure white (#fff) for body text - oklch(0.93 0 0) or similar reduces harshness

Testing both modes

If you support both modes (some enterprise clients require light mode), test systematically:

  1. Contrast ratios - Every text/background combination must meet WCAG AA (4.5:1 for body text, 3:1 for large text)
  2. Colour differentiation - Red/green signals must be distinguishable in both modes. Consider adding shape indicators (arrows, icons) for colour-blind accessibility
  3. Chart readability - Chart colours that work on dark may wash out on light, and vice versa
  4. Border visibility - Subtle borders that separate panels in dark mode may become invisible or too heavy in light mode

The 80/20 rule

For most trading applications, dark mode is the primary mode and light mode is a nice-to-have. Invest heavily in getting the dark mode colour system right. Build it with CSS custom properties from day one so adding light mode later is a theme file change, not a refactor.

Kickstart Your Trading Application

Hedge UI is a React starter kit with production-ready trading components, real-time data handling, and customisable layouts — so you can ship faster.

Get Hedge UI