React Native · Dark Theme

Mobile App Style Guide

Comprehensive design reference for the TrainerDay mobile app. React Native 0.80, Styled Components, dark theme only. Designed for athletes who are sweating, gasping, and need to read numbers from a meter away.

Design Principles

The core ideas that shape every screen, component, and interaction

Friendly, Not Corporate

Rounded corners everywhere. Pill-shaped buttons. Warm blues. No sharp edges, no cold grays. TrainerDay feels like a helpful training buddy, not enterprise software. We want users to smile when they open the app.

Simple and Open

Generous whitespace. Clean hierarchy. One thing at a time. If a screen feels cluttered, remove something. If a user needs to think about how to use it, simplify it. The best UI is the one you don't notice.

Readable While Suffering

The workout screen is used while sweating, gasping, eyes blurring. Target numbers must be 64px+ bold, readable from 1 meter away. Max 3-4 info pieces visible. High contrast, no subtlety. Design for the hardest moment of the ride.

One System, Two Themes

Web and mobile share the same design language -- same primary blue, same font, same periodization colors, same friendly personality. Only the surface colors differ: light for web, dark for mobile. One brand, two contexts.

Color Tokens

All colors from designTokens.colors -- never hardcode hex values

Brand Identity
Primary Blue
#2563eb
Brand Blue
#5B8BE1
Brand Blue Light
#2C68DE
Success Green
#10b981
Danger Red
#C40002
Primary Light
rgba(37,99,235,0.2)
Usage: Primary Blue = Coach Jack blue, the brand anchor. Brand Blue = chart bars, accents. Brand Blue Light = interactive elements (switcher thumbs, sliders).

Surfaces & Backgrounds

The dark layered surface system. Cards sit on backgrounds, modals sit on cards.

Surface Hierarchy (Dark Theme)
App Background
#1A1C26
Surface 1 (cards)
#20232F
Surface 2 (elevated)
#292D3D
Surface 3 (deep)
#161820
Workout Card
#222436
Auth Background
#020202
Border
#3a3d55
Modal Overlay
rgba(0,0,0,0.5)
Surface Layering (Visual)
APP BACKGROUND #1A1C26
SURFACE 1 #20232F
SURFACE 2 #292D3D
SURFACE 3 #161820

Text Color Hierarchy

Four levels of text prominence for creating visual hierarchy

Text Levels
Default (primary)
#FFFFFF
Second (body text)
#d0d0d2
Third (captions)
#83858B
Fourth (disabled)
#525257
Error
#D77171
Blue Accent
#5995F1
Preview
Primary heading text
Secondary descriptive text for supporting content
Tertiary text for captions and metadata
Quaternary text for disabled or decorative elements
Error message text
Blue accent link or action text

Training Zones

Zwift-based zone palette shared across all platforms. Source: @trainerday/cycling-converter

Zone Colors (7 Zones)
Z1 Recovery
#7F7F7F
Z2 Endurance
#3F8FCE
Z3 Tempo
#49C072
Z4 Threshold
#FFCC3F
Z5 VO2max
#F46D41
Z6 Anaerobic
#D6270B
Z7 Neuromuscular
#D6270B

Periodization Colors

Training plan phase indicators -- identical across web and mobile

Phase Colors
Base Build Peak Event
Base #02c9af Build #ffba4a Peak #f86f2b Event #1a9af6
Component-Specific Colors
ComponentRoleValue
Tab BarFocused#2563eb
Tab BarMuted#6E7085
Tab BarContinue (blinks)#48B833
SwitcherThumb On#2C68DE
SwitcherThumb Off#86878B
SwitcherTrack#273551
ChartWorkout Bar#2C68DE (brandBlueLight)
ChartPassed Overlay#273551
ChartProgress Line#1D75E7
ChartFTP Line#e9a30050 (dashed)
SliderThumb#2C68DE
SliderMin Track#3E5C97
SliderMax Track#86878B
IndicatorWarning#C40002
IndicatorOut of Range#C40002
ToolbarButton BG#161820
ToolbarIcon Color#CACACA

Typography

DM Sans everywhere -- five weights available as separate font files in React Native

Font Family
DMSans-Light (300) Light weight for subtle labels
DMSans-Regular (400) Regular weight for body text
DMSans-Medium (500) Medium weight for navigation and labels
DMSans-SemiBold (600) SemiBold weight for headings
DMSans-Bold (700) Bold weight for big numbers and CTAs
In React Native, weight is set via fontFamily (e.g. DMSans-Bold), not fontWeight. Use TDText type="bold" to set the correct family.

Responsive Font Sizing

Workout indicator sizes scale with screen size. Source: src/services/css/font.ts

Workout Indicator Font Sizes by Screen Size
ElementDefault (xSmall)MediumLargeXLarge
Main Target 64px / Bold 68px 72px 76px
Main Target (second) 64px / Medium 68px 72px 88px
Main Unit 16px 28px 28px 28px
Device Value 44px / Medium 44px 44px 80px
Device Unit 12px 12px 12px 24px
Time 40px / Medium 44px 44px 80px
Start Button 16px / Medium 28px 28px 24px
Touch targets: minimum 56px on all workout screens. Screen size breakpoints detected via @/utils/screenInfo.

TDButton

Primary action button -- pill shape, 4 style variants, 2 sizes, optional icon. Always use this, never raw TouchableOpacity.

Style Variants
buttonStyle="main" (default)
buttonStyle="secondary"
buttonStyle="warning-link"
buttonStyle="success"
Sizes and Icons
Standard (46px) vs Large (52px)
height: 46px / font: 15px
height: 52px / font: 17px
With icons
Typical paired layout (most common pattern)

TDText

Base text component -- type prop controls font weight via font family. Never use raw Text.

Weight Variants
Light -- Interval complete type="light"
Regular -- Connect your power meter to get started type="regular"
Medium -- Endurance 180w type="medium"
SemiBold -- Sweet Spot Intervals type="semiBold"
Bold -- 220 W type="bold"
Text colors: default #FFF / second #d0d0d2 / third #83858B / fourth #525257 / error #D77171

TDTextInput

Floating label input -- used on auth screens. Pill-shaped, 56px height, animated label.

Input States
Empty (placeholder centered)
Email
Focused (label floats up)
Email user@example.com
Error (red border)
Email invalid-email
This field is required.
Password (eye toggle)
Password ........
h: 56px / radius: 28px / bg: #020202 / border: rgba(255,255,255,0.2) / focus: 0.4 / error: rgba(220,80,80,0.6) / label: #B0B2BC / input text: #E0E0E4 18px

Switcher

Toggle switch -- native Switch component with custom TrainerDay colors

States
Off
On
51x31px / thumbOn: #2C68DE / thumbOff: #86878B / track: #273551

WorkoutCard

Two display modes: card style (Today tab) and list style (Workouts tab)

Card Style (Today Tab)
Today's Workout
Sweet Spot Intervals -- 30 min
Send To
Ride
bg: #222436 / radius: 16px / title prefix: #5B8DEF / chart bars use zone colors
Workout Chart (Active Workout View)
FTP
0:0015:0030:00
bars: #2C68DE / FTP line: #e9a30050 dashed / passed: #273551 overlay / progress: #1D75E7 vertical line

Zone Badges & Periodization Chips

Training zone indicators used throughout the app for badges, charts, and progress bars

Zone Badges (Zwift-based)
Z1 Recovery Z2 Endurance Z3 Tempo Z4 Threshold Z5 VO2max Z6 Anaerobic Z7 Neuromuscular
Periodization Chips
Base Build Peak Event

Workout Indicators

Live data displays during active workout -- time, power, HR, cadence, target

Time indicator -- 40px medium
12:34
Device indicators -- 44px medium with unit labels
185 W
Power
142 bpm
Heart Rate
88 rpm
Cadence
Target indicator -- 64px bold (THE BIG NUMBER)
220 W
TARGET

Workout Controls

Action buttons during active workout -- 56x56px dark squares with icon

Control Buttons
Start
Pause
Plus
Skip
Finish
56x56px / bg: #20232F / radius: 5px / icon: #CACACA
Workout Toolbar (Bottom)
100%
h: 55px / bg: #20232F / btn: 44x40px bg #161820 radius 8px / icons: #CACACA / intensity: centered percentage

TabBar

Bottom tab navigation -- focused, muted, and blinking continue states

Tab States
Today
Workouts
Continue
Activities
Settings
h: 64px / bg: #1A1C26 / focused: #2563eb / muted: #6E7085 / continue: #48B833 blinks

Settings Row

Two variants: navigation row (56px, with chevron) and switcher row (71px, with toggle)

Settings Rows
Account
Profile
Subscription PRO
FTP
200 W
Preferences
Auto-pause
Pause when you stop pedaling
Sound alerts
Beep on interval changes
Nav rows: 56px h, bg #20232F, chevron #83858B / Toggle rows: 71px h, title + description + switch / 1px gap separator

TDPopup / Bottom Sheet

Dark surface popup overlay with close button, title, content, and action button

Modal / Popup Example
Devices
Wahoo KICKR
Power Meter
Connected
Garmin HRM-Pro
Heart Rate
Connecting...
bg: #20232F / radius: 12px / overlay: rgba(0,0,0,0.5) / close: 36x36 bg #2a2d3d radius 12px

Active Workout Screen

Full vertical stack layout of the WorkoutPlayer screen

Active Workout
Sweet Spot Intervals
12:34
POWER
185 W
HR
142 bpm
220
TARGET
85%
Layout stack (top to bottom):
Status bar -- 44px
Header -- 50px
Time -- 62px
Device indicators -- 62px
Main target -- 84px
Controls row -- 56px
Chart area -- flex-grow (fills remaining)
Bottom toolbar -- 48px
Safe area -- 34px

Key rules:
Target power: 64px bold, most dominant element
Device values: 44px medium, secondary
Control buttons: 56x56px, bg #20232F, radius 5px
Chart: blue bars (#2C68DE), passed bars (#273551)
FTP dashed line, progress line (#1D75E7)
Bottom toolbar: bg #20232F, button bg #161820

Workout Screen Rules

Non-negotiable constraints for the active workout experience

Critical -- Design for the Hardest Moment
TrainerDay is used by athletes while sweating, breathing hard, eyes blurred. Design for the hardest moment of the ride.

Golden Rules

The non-negotiable constraints

Always
  • Use designTokens.colors for all colors
  • Use TDButton for buttons, TDText for text
  • Pill-shaped buttons (radius 9999px)
  • DM Sans everywhere, no exceptions
  • 64px+ bold for workout target numbers
  • 56px minimum touch targets on workout screens
  • One primary blue button per screen
  • Use TDTextInput for all text inputs
  • Use primitives from @/services/css
  • Dark surface (#20232F) for cards on dark bg (#1A1C26)
  • Use #83858B for unit labels and secondary text
  • Settings rows: 56px height, 1px gap separator
Never
  • Hardcode hex colors -- always use tokens
  • Use StyleSheet.create -- styled-components only
  • Use raw Text, TextInput, or custom buttons
  • Small text (<14px) for anything during a workout
  • Sharp corners -- minimum 4px radius
  • Cluttered workout screens -- max 3-4 info pieces
  • System fonts or anything other than DM Sans
  • Bright/light backgrounds -- dark theme only
  • Multiple primary buttons competing for attention
  • Subtle color differences for important state changes
  • Small touch targets (<44px) anywhere
  • Use legacy components (RedButton, TransparentButton, etc.)

Component → React Native Mapping

How each design catalog element maps to the actual React Native codebase

Catalog ElementRN ComponentImport PathKey Props
Blue pill button TDButton @/components/TDButton buttonStyle="main|secondary|warning-link|success", title, testID
X close icon ButtonClose @/components/ButtonClose testID, onClose
Any text TDText @/components/TDText type="light|regular|medium|semiBold|bold"
Floating label input TDTextInput @/components/TDTextInput label, testID, isValid?, error?, secureTextEntry?
Checkbox TDCheckbox @/components/TDCheckbox isChecked, onToggle, label?, testID
Toggle switch Switcher @/components/Switcher value, onValueChange, testID
Dropdown TDPicker @/components/TDPicker data, value, onChange, testID?
PRO badge ProBadge @/components/ProBadge (no props)
Workout card WorkoutCard @/components/WorkoutChart/WorkoutCard workout, width, ftp, segments, isCardStyle?
Navigation header HeaderWithButtonGoBack @/components/HeaderWithButtonGoBack title, testID, onBack?
Modal frame TDPopup @/components/TDPopup isVisible, onClose, title?, showCloseButton?
Settings nav row SettingsButtonGoTo @/screens/Settings/components/SettingsButtonGoTo title, screen, testID
Settings toggle row SettingsSwitcher @/screens/Settings/components/SettingsSwitcher title, description, value, onChange, testID
Offline message NoInternetConnection @/components/NoInternetConnection (no props)
Guest sign-in card GuestModeMessage @/components/GuestModeMessage (no props)

TrainerDay Mobile Design System -- Home / Shared / Web / Desktop / Marketing

Source: src/services/css/themes/designTokens.ts / src/services/css/colors.ts / src/services/css/font.ts / src/services/css/fontFamily.ts