How to disable dark mode in iOS

⋅ 6 min read ⋅ iOS UIKit Dark Mode

Table of Contents

Since iOS 13 (Xcode 11), every app has a dark mode enabled by default. But if you are not ready to adopt it, you can disable it.

I group the way we disable dark in iOS into two categories.

  1. Disable dark mode for an entire app.
  2. Disable dark mode for some part of an app, e.g., view, view controller.

Disable dark mode for an entire app

If you want to disable dark mode for an entire app, you have two ways to do it.

  1. Info.plist.
  2. UIWindow overrideUserInterfaceStyle property.

Info.plist

To control an interface style[1] for an entire app, you simply set UIUserInterfaceStyle (Appearance) key[2] in your Info.plist file.

You can assign it to either Light or Dark value to force a light and dark user interface style.

<key>UIUserInterfaceStyle</key>
<string>Light</string>
Set Appearance (UIUserInterfaceStyle) key to Light will disable dark mode for an entire app.
Set Appearance (UIUserInterfaceStyle) key to Light will disable dark mode for an entire app.

UIWindow overrideUserInterfaceStyle property

In iOS 13, every UIView got a new property, overrideUserInterfaceStyle, to control which interface style (light, dark, unspecified) that the view will adopt. Normally, when you assign an UIUserInterfaceStyle to a view, the style applies to the view and all of the subviews owned by the same view controller. But UIWindow, which is also a UIView subclass, got special treatment.

If the view is a UIWindow object, the new style applies to everything in the window, including the root view controller and all presented content.

So, you could set a window's overrideUserInterfaceStyle property to control interface style for the whole app.

window?.overrideUserInterfaceStyle = .light

The difference between Info.plist and overrideUserInterfaceStyle

The main difference between using setting overrideUserInterfaceStyle on a window and Info.plist is you can change interface style dynamically with overrideUserInterfaceStyle method.

Imagine you put dark mode behind a pay-wall. The code that controls access to dark mode might look something like this.

let paidUser = true

if paidUser {
window?.overrideUserInterfaceStyle = .unspecified
} else {
window?.overrideUserInterfaceStyle = .light
}

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Disable dark mode for some part of an app

You can also disable dark mode in both UIView and UIViewController.

UIView

Like mentioned earlier in the last section, UIView got overrideUserInterfaceStyle property to control an interface style. When you assign a value to a view overrideUserInterfaceStyle property, the style applies to the view and all of the subviews owned by the same view controller.

view.overrideUserInterfaceStyle = .light

UIViewController

Just like views, view controllers also get the overrideUserInterfaceStyle property. If you assign a value to a view controller overrideUserInterfaceStyle property, the new style applies to the view controller, its entire view hierarchy, and any embedded child view controllers.

override func viewDidLoad() {
super.viewDidLoad()

overrideUserInterfaceStyle = .light
}

The difference between setting overrideUserInterfaceStyle on view controller and root view

On the surface, it looks like we can disable dark mode for an entire view controller by setting overrideUserInterfaceStyle to .light on both view controller and root view since the style applies to an entire view hierarchy. But there is a minor difference.

Set overrideUserInterfaceStyle on a view controller and a view controller root view yield almost the same result. The only difference is setting overrideUserInterfaceStyle on a view controller also affects embedded child view controllers.

Let's see this in action. We create two view controllers, ViewController and SecondViewController. SecondViewController is the one we will embed into ViewController.

SecondViewController is a simple view controller with a background of .secondarySystemBackground.

class SecondViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .secondarySystemBackground
}
}

We embed SecondViewController as a child view controller of ViewController, taking the right half of the screen.

class ViewController: UIViewController {
let vc2 = SecondViewController()

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = .systemBackground

self.addChild(vc2)
vc2.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vc2.view)
vc2.didMove(toParent: self)

NSLayoutConstraint.activate([
vc2.view.topAnchor.constraint(equalTo: view.topAnchor),
vc2.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
vc2.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
vc2.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
}
}

By default, all views adapt to systemwide user interface style. Try switching between light and dark mode, and an entire app change accordingly.

Views from both view controllers change simultaneously.
Views from both view controllers change simultaneously.

Now, let try setting the overrideUserInterfaceStyle property on the view and view controller to see the difference.

UIViewController

By setting overrideUserInterfaceStyle on a view controller, the new style applies to the view controller, its entire view hierarchy, and any embedded child view controllers (SecondViewController's view). That's mean everything are force to light mode with overrideUserInterfaceStyle = .light.

class ViewController: UIViewController {
let vc2 = SecondViewController()

override func viewDidLoad() {
super.viewDidLoad()

overrideUserInterfaceStyle = .light
view.backgroundColor = .systemBackground

...
}
}

Everything stays in light user interface style, even when the systemwide style is set to dark.

Everything stays in light user interface style, even when the systemwide style is set to dark.
Everything stays in light user interface style, even when the systemwide style is set to dark.

UIView

Setting overrideUserInterfaceStyle on a view would only apply that style to the view and all of the subviews owned by the same view controller. That's mean an embed view from SecondViewController won't get affect by view.overrideUserInterfaceStyle = .light and still support light and dark appearance.

class ViewController: UIViewController {
let vc2 = SecondViewController()

override func viewDidLoad() {
super.viewDidLoad()

view.overrideUserInterfaceStyle = .light
view.backgroundColor = .systemBackground

...
}
}

The view from SecondViewController still supports light and dark mode while ViewController's view stays in light mode.

Set overrideUserInterfaceStyle to view only affects all of the subviews owned by the same view controller.
Set overrideUserInterfaceStyle to view only affects all of the subviews owned by the same view controller.

So, if you want to disable dark mode for an entire view controller, you better set overrideUserInterfaceStyle on a view controller.


  1. This is the term Apple refers to light and dark mode, UIUserInterfaceStyle ↩︎

  2. iOS Keys https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW44 ↩︎


Read more article about iOS, UIKit, Dark Mode, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
What do @main, @UIApplicationMain, and @NSApplicationMain mean

When you start a new project, you would see either of these attributes in an AppDelegate file. Let's find out its functionality.

Next
How to decode enums ignoring case in Swift Codable

Learn how to make a case insensitive enum.

← Home