Dark Mode
If your app has its own dark mode, you should toggle it on and off in sync with the system’s dark mode setting. You can do this by using the [prefer-color-scheme] CSS media query.
If you want to manually switch between light/dark modes, you can do this by
setting the desired mode in the
themeSource
property of the module. This property’s value will be propagated
to your Renderer process. Any CSS rules related to prefers-color-scheme
will
be updated accordingly.
In macOS 10.14 Mojave, Apple introduced a new
for all macOS computers. If your Electron app has a dark mode, you can make it
follow the system-wide dark mode setting using
the nativeTheme
api.
In macOS 10.15 Catalina, Apple introduced a new “automatic” dark mode option
for all macOS computers. In order for the nativeTheme.shouldUseDarkColors
and
Tray
APIs to work correctly in this mode on Catalina, you need to use Electron
>=7.0.0
, or set NSRequiresAquaSystemAppearance
to false
in your
Info.plist
file for older versions. Both
and Electron Forge have a
to automate the Info.plist
changes during app build time.
If you wish to opt-out while using Electron > 8.0.0, you must
set the NSRequiresAquaSystemAppearance
key in the Info.plist
file to
true
. Please note that Electron 8.0.0 and above will not let you opt-out
of this theming, due to the use of the macOS 10.14 SDK.
This example demonstrates an Electron application that derives its theme colors from the . Additionally, it provides theme toggle and reset controls using IPC channels.
Starting with the index.html
file:
Hello World!
Current theme source: System
The example renders an HTML page with a couple elements. The <strong id="theme-source">
element shows which theme is currently selected, and the two <button>
elements are the
controls. The CSS file uses the prefers-color-scheme
media query
to set the <body>
element background and text colors.
```js title=’preload.js’ const { contextBridge, ipcRenderer } = require(‘electron’)
contextBridge.exposeInMainWorld(‘darkMode’, { toggle: () => ipcRenderer.invoke(‘dark-mode:toggle’), system: () => ipcRenderer.invoke(‘dark-mode:system’) })
Using addEventListener
, the file adds 'click'
to each button element. Each event listener handler makes calls to the respective window.darkMode
API methods.
Finally, the main.js
file represents the main process and contains the actual nativeTheme
API.
The ipcMain.handle
methods are how the main process responds to the click events from the buttons
on the HTML page.
The 'dark-mode:toggle'
IPC channel handler method checks the shouldUseDarkColors
boolean property,
sets the corresponding themeSource
, and then returns the current shouldUseDarkColors
property.
Looking back on the renderer process event listener for this IPC channel, the return value from this
handler is utilized to assign the correct text to the <strong id='theme-source'>
element.
The 'dark-mode:system'
IPC channel handler method assigns the string 'system'
to the themeSource
and returns nothing. This also corresponds with the relative renderer process event listener as the
method is awaited with no return value expected.