iOS Simulator
Dark Mode
iOS Development
App Testing
Developer Tools

How to use dark mode in iOS simulator?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

To enable dark mode in the iOS Simulator, go to Settings > Display & Brightness in the simulated device and select Dark, or toggle it from Xcode's debug bar using the Environment Overrides panel. You can also switch appearance instantly from the terminal with xcrun simctl ui <device> appearance dark. All three approaches do the same thing, but the terminal command is the fastest for developers who switch frequently during testing.

Dark mode testing is not optional for any app that ships to the App Store. If your colors, images, or text rely on a light background, dark mode will expose those assumptions immediately. The Simulator provides every tool you need to validate both appearances without deploying to a physical device.

Method 1: Settings App in the Simulator

This mirrors exactly what a user does on a real iPhone or iPad.

  1. Open the Simulator (launch it from Xcode or run open -a Simulator in Terminal).
  2. Navigate to Settings > Display & Brightness.
  3. Under Appearance, tap Dark.

The change takes effect immediately. Every app on the simulated device switches to dark mode, including the home screen and system UI.

To switch back, tap Light in the same settings panel.

Automatic Appearance Schedule

The Simulator also supports the automatic light/dark schedule. Under Display & Brightness > Automatic, you can set the appearance to change based on a schedule. This is useful for testing how your app handles dynamic appearance changes without manually toggling.

Method 2: Xcode Environment Overrides

This is the fastest method when you are already debugging an app in Xcode.

  1. Run your app on the Simulator from Xcode.
  2. In Xcode's debug area (bottom toolbar), click the Environment Overrides button (it looks like a small slider icon, or find it under Debug > View Debugging > Environment Overrides).
  3. Toggle Interface Style to Dark.

The override takes effect immediately while your app is running. It does not change the Simulator's system-level setting, so other apps still appear in their previous mode.

This is particularly useful for toggling back and forth rapidly while inspecting layout changes, because the toggle is a single click.

Method 3: Terminal Command with simctl

The simctl command-line tool controls the Simulator from Terminal. This is the best approach for scripting, CI pipelines, or developers who prefer the keyboard.

bash
1# Switch to dark mode
2xcrun simctl ui booted appearance dark
3
4# Switch to light mode
5xcrun simctl ui booted appearance light
6
7# Check current appearance
8xcrun simctl ui booted appearance

The booted keyword targets whatever Simulator is currently running. If multiple Simulators are running, replace booted with a specific device UDID.

bash
1# List available simulators and their UDIDs
2xcrun simctl list devices
3
4# Target a specific simulator
5xcrun simctl ui 4A2B7C8D-1234-5678-ABCD-EF0123456789 appearance dark

Integrating with Screenshot Tests

For automated UI testing, you can set the appearance before launching your test suite.

bash
1#!/bin/bash
2# Capture screenshots in both modes
3
4xcrun simctl ui booted appearance light
5xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'
6
7xcrun simctl ui booted appearance dark
8xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'

Method Comparison

MethodSpeedRequires Xcode Debug SessionScriptablePersists After App Restart
Settings appSlow (navigate through UI)NoNoYes
Environment OverridesFast (one click)YesNoNo (override only)
xcrun simctl uiFastest (command line)NoYesYes

Implementing Dark Mode Support in Your App

Testing dark mode is only useful if your app actually adapts to the appearance. Here are the key implementation patterns.

System Colors

UIKit provides semantic colors that automatically adapt. Using these is the simplest path to dark mode support.

swift
label.textColor = .label           // Black in light, white in dark
view.backgroundColor = .systemBackground  // White in light, black in dark
detailLabel.textColor = .secondaryLabel    // Gray, adapts to both modes

Custom Dynamic Colors

When system colors are not sufficient, define colors that resolve differently based on the current trait collection.

swift
1let cardBackground = UIColor { traitCollection in
2    switch traitCollection.userInterfaceStyle {
3    case .dark:
4        return UIColor(red: 0.15, green: 0.15, blue: 0.17, alpha: 1.0)
5    default:
6        return UIColor(red: 0.97, green: 0.97, blue: 0.98, alpha: 1.0)
7    }
8}
9
10cardView.backgroundColor = cardBackground

Asset Catalog Variants

For images, icons, and color definitions, Xcode's asset catalog supports appearance variants directly.

  1. Select an image or color in Assets.xcassets.
  2. In the Attributes Inspector, set Appearances to Any, Dark (or Any, Light, Dark).
  3. Drag the appropriate assets into each slot.

At runtime, UIKit automatically picks the correct variant based on the current appearance. No code changes required.

SwiftUI

SwiftUI uses the @Environment property wrapper to react to appearance changes.

swift
1struct ContentView: View {
2    @Environment(\.colorScheme) var colorScheme
3
4    var body: some View {
5        Text("Hello, World!")
6            .foregroundColor(colorScheme == .dark ? .white : .black)
7            .background(colorScheme == .dark ? Color.black : Color.white)
8    }
9}

For most cases, using SwiftUI's built-in semantic colors (Color.primary, Color.secondary, Color(.systemBackground)) is sufficient and does not require reading colorScheme manually.

Detecting Appearance Changes at Runtime

If your app needs to react programmatically when the user toggles dark mode (for example, to update a non-UIKit component), override traitCollectionDidChange.

swift
1override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
2    super.traitCollectionDidChange(previousTraitCollection)
3
4    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
5        // Update non-UIKit components, charts, WebViews, etc.
6        updateChartColors()
7    }
8}

Debugging Dark Mode Issues

Color Contrast Verification

Use the Accessibility Inspector (open from Xcode > Open Developer Tool > Accessibility Inspector) to verify contrast ratios meet WCAG standards. The tool overlays contrast information on the Simulator in real time.

View Hierarchy Debugger

Xcode's View Debugger (Debug > View Debugging > Capture View Hierarchy) lets you inspect which colors each view is using. Look for hard-coded colors (white backgrounds, black text) that do not adapt.

Overriding Appearance Per View Controller

For testing, you can force a specific appearance on a single view controller.

swift
1// Force dark mode regardless of system setting
2overrideUserInterfaceStyle = .dark
3
4// Force light mode
5overrideUserInterfaceStyle = .light
6
7// Follow system setting (default)
8overrideUserInterfaceStyle = .unspecified

This is useful for comparing the two modes side by side in split-view debugging scenarios.

Common Pitfalls

  • Hard-coding colors like UIColor.white or UIColor.black instead of using semantic colors. These do not adapt and look wrong in the opposite mode. Use .systemBackground, .label, and the other semantic alternatives.
  • Forgetting to provide dark variants for images in the asset catalog. A bright logo on a dark background, or a dark icon on a dark background, becomes invisible or jarring.
  • Testing only with Environment Overrides and not with the Settings app. Environment Overrides do not persist, so you miss bugs that appear on app launch in dark mode (e.g., launch screen colors).
  • Not testing the transition between modes. Users can switch modes while your app is in the foreground. If you cache colors at startup without listening for trait changes, the UI will show stale colors after a switch.
  • Assuming traitCollectionDidChange fires on every appearance change in SwiftUI. In SwiftUI, use @Environment(\.colorScheme) instead. The UIKit callback is for UIKit-based views.
  • Setting overrideUserInterfaceStyle = .dark in production code. This is a debugging tool. Shipping it disables the user's system preference for your entire app.

Summary

  • Enable dark mode in the iOS Simulator via the Settings app, Xcode's Environment Overrides, or xcrun simctl ui booted appearance dark.
  • The simctl terminal command is the fastest option and is scriptable for CI and automated screenshot testing.
  • Use UIKit semantic colors (.label, .systemBackground) and asset catalog variants to support both appearances with minimal code.
  • In SwiftUI, @Environment(\.colorScheme) provides reactive appearance tracking.
  • Override traitCollectionDidChange in UIKit to handle dynamic appearance switches for non-standard components.
  • Always test both the initial launch in dark mode and the live transition between modes.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.