Skip to content

Add a "System" option to the dark/light mode setting (follow OS appearance) #5638

Open

Description

@fabianfrankwerner

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.tsx already configures next-themes with defaultTheme="system" and enableSystem, so a first-time visitor with no stored preference gets system behaviour.
  • apps/dokploy/components/ui/modeToggle.tsx only ever calls setTheme("dark") / setTheme("light"), and next-themes persists that choice to localStorage.

The consequence is that "system" is effectively a one-time default and not a mode:

  1. After a single click on the toggle, the stored preference is a fixed light or dark.
  2. From that point on there is no UI anywhere in Dokploy that can restore "system". The only way back is manually clearing localStorage.
  3. 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 Button exactly as it is today, including the Sun/Moon rotate + scale CSS animation classes, and use it as the DropdownMenuTrigger.
  • The trigger icon keeps reflecting the resolved appearance (driven by the dark class on <html>, which next-themes already 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 DropdownMenuRadioGroup with a DropdownMenuRadioItem per option so the current selection is checked and screen-reader accessible.
  • Add a mounted guard for the radio value only, so the checkmark does not cause a hydration mismatch (theme is undefined on 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. localStorage via next-themes already 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.tsx already exports DropdownMenuRadioGroup and DropdownMenuRadioItem, 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

  1. linear-code commented on Oct 9, 2026

    @linear-code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions