Repository navigation
Add a "System" option to the dark/light mode setting (follow OS appearance) #5638
Description
What problem will this feature address?
Dokploy currently only offers a two-state theme toggle. There is no way to select "follow the OS / system appearance" as an explicit, sticky choice.
The relevant code:
apps/dokploy/pages/_app.tsxalready configuresnext-themeswithdefaultTheme="system"andenableSystem, so a first-time visitor with no stored preference gets system behaviour.apps/dokploy/components/ui/modeToggle.tsxonly ever callssetTheme("dark")/setTheme("light"), andnext-themespersists that choice tolocalStorage.
The consequence is that "system" is effectively a one-time default and not a mode:
- After a single click on the toggle, the stored preference is a fixed
lightordark. - From that point on there is no UI anywhere in Dokploy that can restore
"system". The only way back is manually clearinglocalStorage. - Consequently the UI stops following OS-level appearance changes (macOS/iOS Dark Mode switch, Chrome/Safari per-site theme, forced-colors / high-contrast profiles on Windows and Linux desktops, GNOME/KDE "Night Light"-style scheduled switches).
This matters for self-hosters in particular: Dokploy is a self-hosted panel that is usually opened in a browser tab alongside other tools, and several of those users change their OS appearance on a schedule (night shift, dark mode toggling with daylight). They currently have to pick one mode and lose the other.
There is precedent that this is a real request: PR #3163 (feat: add support for a system theme) attempted to add it and was closed without merging, with feedback that the implementation over-engineered a simple toggle, dropped the existing CSS animations, and had a bug in the sr-only span. This issue is intended to re-propose the feature with a minimal implementation that keeps the current visuals intact.
Describe the solution you'd like
Turn the existing single button into a small dropdown with three explicit, selectable options:
- Light — forces light
- Dark — forces dark
- System — follows the OS, and keeps following it live
Concretely, the least invasive version that preserves the current look and feel:
- Keep the existing
Buttonexactly as it is today, including theSun/Moonrotate+scaleCSS animation classes, and use it as theDropdownMenuTrigger. - The trigger icon keeps reflecting the resolved appearance (driven by the
darkclass on<html>, whichnext-themesalready sets during the pre-hydration script). So in "System" mode the icon still shows a sun on a light OS and a moon on a dark OS, and the animation still plays when the OS theme changes. This is what makes the mode legible at a glance without needing a third icon on the trigger. - Add a
DropdownMenuRadioGroupwith aDropdownMenuRadioItemper option so the current selection is checked and screen-reader accessible. - Add a
mountedguard for the radiovalueonly, so the checkmark does not cause a hydration mismatch (themeisundefinedon the first render).
No new dependency, no change to _app.tsx (it already has enableSystem), and sonner.tsx already forwards "system" through to its toaster, so toast styling stays correct.
Describe alternatives you've considered
- Keep the button and cycle through light → dark → system on each click. Fewer lines, but the current mode is not visible without clicking, and a stray click silently changes behaviour. It also requires the trigger icon to change per mode, which is what caused the confusion discussed in feat: add support for a system theme #3163 (the icon showing "dark" while the OS is dark). A dropdown makes the state explicit.
- Add the option to Settings and keep the button as a two-state toggle. Rejected because it still leaves the quick-access control misleading, and it spreads the setting across two places for a preference users expect to change often.
- Persist a per-user preference in the database instead of
localStorage. Out of scope for this request.localStoragevianext-themesalready works for a per-browser preference, and doing it server-side would require schema changes, an API route and permission handling for a purely cosmetic setting.
Additional context
- Affected file:
apps/dokploy/components/ui/modeToggle.tsx - Only consumer today:
apps/dokploy/components/layouts/user-nav.tsx(renders<ModeToggle />inside the account dropdown next to the "My Account" label), so the change is contained and does not affect other layouts. apps/dokploy/components/ui/dropdown-menu.tsxalready exportsDropdownMenuRadioGroupandDropdownMenuRadioItem, so no new primitive is needed.- Reference: Implement Light Mode Feature #1155 (the original light mode feature) and feat: add support for a system theme #3163 (previous attempt at a system theme).
I have a minimal implementation ready that keeps the existing animations and fixes the accessibility bug flagged in #3163, and I will open it as a PR against canary.
Activity
linear-code commentedon Oct 9, 2026
DOK-851