From b4d30a168b819669353128ff79bb304b229d11a5 Mon Sep 17 00:00:00 2001 From: nickl-portainer Date: Fri, 24 Jul 2026 15:17:47 +1200 Subject: [PATCH] feat(theme): listen for system theme changes [R8S-1190] (#3265) --- app/react/portainer/services/applyTheme.ts | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/app/react/portainer/services/applyTheme.ts b/app/react/portainer/services/applyTheme.ts index 9a3ab6e0b8..ec9becbe1a 100644 --- a/app/react/portainer/services/applyTheme.ts +++ b/app/react/portainer/services/applyTheme.ts @@ -1,14 +1,31 @@ import { ThemeColor } from '@/portainer/users/types'; +let removeAutoThemeListener: (() => void) | null = null; + export function applyTheme(color: ThemeColor) { + removeAutoThemeListener?.(); + removeAutoThemeListener = null; + if (color === 'auto' || !color) { - const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - if (isDark) { - document.documentElement.setAttribute('theme', 'dark'); - } else { - document.documentElement.removeAttribute('theme'); + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + function handleChange() { + applyAutoTheme(mediaQuery); } + + applyAutoTheme(mediaQuery); + mediaQuery.addEventListener('change', handleChange); + removeAutoThemeListener = () => + mediaQuery.removeEventListener('change', handleChange); } else { document.documentElement.setAttribute('theme', color); } } + +function applyAutoTheme(mediaQuery: MediaQueryList) { + if (mediaQuery.matches) { + document.documentElement.setAttribute('theme', 'dark'); + } else { + document.documentElement.removeAttribute('theme'); + } +}