VS Code recently added the ability to switch themes when macOS's dark mode changes. Presumably they use the Electron API, which internally uses the Objective-C API of subscribing to the AppleInterfaceThemeChangedNotification event in NSDistributedNotificationCenter.

It would be nice if Emacs had this same ability. The pseudo-code would be:

(add-event 'os-dark-mode-changed
  (lambda (on)
    (set-theme (if on

(In VS Code, the dark and light themes are configurable.)

Does Emacs have the ability to do something similar?

  • Maybe you can periodically query the dark mode status.
    – Juancho
    Feb 11, 2020 at 1:04
  • 1
    Then I'd have to poll, whereas macOS already provides an event for this. There was a reddit thread on this solution and it was generally thought of as being bad practice.
    – Steven
    Feb 11, 2020 at 19:22
  • 2
    I’ve submitted a patch which provides an ns-dark-mode-change-hook which you could use to do this. Hopefully it will be accepted, and then a future version of Emacs will have this feature!
    – dpk
    Mar 9, 2021 at 15:32

2 Answers 2


Using emacs-plus this is easy. See the docs, but here is the code in any case.

(defun my/apply-theme (appearance)
  "Load theme, taking current system APPEARANCE into consideration."
  (mapc #'disable-theme custom-enabled-themes)
  (pcase appearance
    ('light (load-theme 'tango t))
    ('dark (load-theme 'tango-dark t))))

(add-hook 'ns-system-appearance-change-functions #'my/apply-theme)

A work-around, more so than an answer: you can change your theme from an external process, by starting your main editor instance in server mode, and using emacsclient. E.g.



emacsclient --eval "(my/dark-mode)" --quiet -no-wait --suppress-output -a true

It turns out that iTerm2 allows you to execute an arbitrary Python script on OS theme changes. You can use this to change iTerm2's own theme, but nothing stops you from adding a cheeky call to emacsclient and controlling Emacs along, with it.

I've combined all of this here: https://gist.github.com/hraban/8eb4ab5c110828a9d1b8c16b4f78193e.

Upside: no polling, no Emacs UI blocking, etc

Downside: iTerm2 must be running.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.