Dark Mode Toggle is a lightweight, fully client-side Reactive Web Block for OutSystems that provides an instant dark/light mode switcher for any Reactive Web application. It applies theme colors globally across the entire app using CSS variables, remembers the user's preference in localStorage, and supports automatic detection of the system's dark/light preference.
No external libraries required — built entirely with vanilla JavaScript and OutSystems Reactive Web.
SetDarkMode
GetCurrentMode
Default
#ffffff
#1a1a2e
#0057D9
Sunset
#fff8f0
#2d1b00
#ff6b35
Ocean
#f0f8ff
#001428
#00b4d8
Forest
#f0fff4
#0d2818
#2d6a4f
Ctrl+Q
DarkModeLib
DarkModeToggle
DarkModeConfig
ToggleDarkMode
Placing the toggle in your Layout Block makes it available on every screen automatically — this is the recommended approach.
LayoutTopMenu
LayoutSideMenu
DMConfig
CurrentMode
"Light"
DMConfig.Style = "Both" DMConfig.DefaultMode = "Auto" DMConfig.Theme = "Default" DMConfig.RememberPreference = True DMConfig.TransitionSpeed = 300
Config = DMConfig
OnModeChanged
ModeChanged
CurrentMode = Mode
Add these to your main application stylesheet to ensure dark mode overrides OutSystems default styles:
body { background-color: var(--dm-bg) !important; color: var(--dm-text) !important; } .app-content, .main-content, [class*="layout"] { background-color: var(--dm-bg) !important; color: var(--dm-text) !important; } input, textarea, select, .form-control { background-color: var(--dm-surface) !important; color: var(--dm-text) !important; border-color: var(--dm-border) !important; }
In your screen containers and cards use CSS variables for colors:
/* Example card */ .my-card { background-color: var(--dm-surface); color: var(--dm-text); border: 1px solid var(--dm-border); }
Ctrl+P
Config
Mode
Style
"Toggle"
DefaultMode
"Auto"
Theme
"Default"
RememberPreference
True
TransitionSpeed
300
Toggle
Icon
Both
Light
Dark
Auto
Switches between dark and light mode programmatically.
NewMode
Returns the currently active mode.
Forces a specific mode — useful for programmatic control.
These variables are set globally and available in any screen stylesheet:
--dm-bg
--dm-text
#333333
--dm-surface
#f5f5f5
#16213e
--dm-border
#e0e0e0
#0f3460
--dm-accent
Layout Block — On Initialize └── Assign: DMConfig.Style = "Both" DMConfig.DefaultMode = "Auto" DMConfig.Theme = "Default" DMConfig.RememberPreference = True DMConfig.TransitionSpeed = 300 Layout Block — Header Menu (Right Side) └── DarkModeToggle ├── Config = DMConfig └── OnModeChanged → ModeChanged action └── Assign: CurrentMode = Mode
DMConfig.Style = "Toggle" DMConfig.DefaultMode = "Light" DMConfig.Theme = "Default"
Shows only the animated toggle switch — clean and minimal.
DMConfig.Style = "Icon" DMConfig.DefaultMode = "Auto" DMConfig.Theme = "Ocean"
Shows only ☀️ in light mode and 🌙 in dark mode — great for compact menus.
DMConfig.DefaultMode = "Dark" DMConfig.RememberPreference = False
App always starts in dark mode and does not remember user changes.
Dark Mode Button → OnClick └── SetDarkMode └── Mode = "Dark"
Programmatically force dark mode from anywhere in your app.
Some Action ├── GetCurrentMode │ └── Output: CurrentMode │ └── If CurrentMode = "Dark" └── Do something for dark mode └── If CurrentMode = "Light" └── Do something for light mode
In any screen's container or card style property:
/* Apply to any container */ background-color: var(--dm-surface); color: var(--dm-text); border: 1px solid var(--dm-border); border-radius: 8px; padding: 16px;
This automatically switches colors when dark mode is toggled — no extra code needed.
On Initialize ├── If CurrentUser.IsAdmin │ └── Assign: DMConfig.Theme = "Ocean" │ └── If Not CurrentUser.IsAdmin └── Assign: DMConfig.Theme = "Default"
Cause: Those elements use hardcoded colors instead of CSS variables.
Fix:Replace hardcoded colors in your stylesheets with CSS variables:
/* Before */ background-color: #ffffff; color: #333333; /* After */ background-color: var(--dm-bg); color: var(--dm-text);
Cause: OutSystems platform CSS has higher specificity.
Fix:Add !important to your app stylesheet:
!important
body { background-color: var(--dm-bg) !important; color: var(--dm-text) !important; }
Cause: RememberPreference is set to False or localStorage is blocked.
False
Fix:
DMConfig.RememberPreference = True
console.log(localStorage.getItem("dm_preference"));
Should return "Dark" or "Light" — if null, localStorage is blocked.
"Dark"
Cause: Browser does not support prefers-color-scheme media query.
prefers-color-scheme
Fix:This is a browser limitation. Set a specific DefaultMode as fallback:
DMConfig.DefaultMode = "Light"
Modern browsers (Chrome, Firefox, Safari, Edge) all support prefers-color-scheme.
Cause: TransitionSpeed set too low or CSS transition being overridden.
DMConfig.TransitionSpeed = 300
*
Cause: Event not wired correctly on the block.
Cause: Toggle placed on individual screen instead of Layout Block.
Fix:Move the DarkModeToggle block to your Layout Web Block so it appears on every screen automatically. See Installation Guide Step 3.
Cause: Dark mode is applied after the page renders (On After Render).
Fix:Add this inline style to your app's index.html or layout's header to prevent flash:
index.html
// Add JS node in Layout's On Initialize (before On After Render) var saved = localStorage.getItem("dm_preference"); if (saved === "Dark") { document.documentElement.setAttribute("data-theme", "dark"); document.body.style.backgroundColor = "#1a1a2e"; }
DefaultMode = "Auto"
var(--dm-surface)
var(--dm-bg)
var(--dm-accent)
TransitionSpeed = 0
Documentation Version: 1.0.0 Component Version: 1.0.0 Last Updated: 2026 Author: Vinayak Siddhiwal.