After searching everywhere online without finding a solid solution, I’ve decided to share a simple and effective way to detect the system theme in Bubble.
Goals:
- Automatically detect whether the user’s system is in light or dark mode and apply the corresponding theme.
- If the user manually selects a theme (light or dark), the automatic system detection will be disabled.
- If the user switches their device theme while using the site, the change will be detected and applied instantly.
Demo
Let’s walk through how to make this happen!
Setup
Step 1:
Install the Toolbox plugin — this allows you to run JavaScript in your Bubble app.
Step 2:
Create an Option Set called Theme
with three options:
System
Light
Dark
Step 3:
In your User data type, add two new fields:
Theme
(type: Theme) — to store the user’s selected themeDark_mode
(type: yes/no) — to track whether dark mode should be applied
Building It Out
Step 1:
Add a “JavaScript to Bubble” element to your page:
- Set the
bubble_fn_suffix
totheme_change
- Enable
Trigger event
andPublish value
- Set value type to
yes/no
Step 2:
Create a workflow on the “JavaScript to Bubble” element:
- Action: Make changes to Current User
- Set
Dark_mode = This JavaScript to Bubble's value
- Only run this when Current User’s Theme is “System”
Step 3:
On Page Load, run the following JavaScript:
if (!window._themeListenerAttached) {
window._themeListenerAttached = true;
const checkAndSendTheme = () => {
// ✅ Check if matchMedia is supported and usable
if (window.matchMedia && typeof window.matchMedia('(prefers-color-scheme: dark)').matches === 'boolean') {
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
bubble_fn_theme_change(isDark ? 'yes' : 'no'); // 👈 output "yes" or "no"
} else {
// ❌ Fallback to light mode if not supported
bubble_fn_theme_change('no');
}
};
// Initial check
checkAndSendTheme();
// Watch for theme changes
if (
window.matchMedia &&
typeof window.matchMedia('(prefers-color-scheme: dark)').addEventListener === 'function'
) {
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', () => {
checkAndSendTheme();
});
}
}
Step 4:
Create a UI element (dropdown, repeating group, etc.) to let users choose between:
- System
- Light
- Dark
Step 5:
Add conditional workflows based on user selection:
- If
Light
is selected:
→ SetUser's Theme = Light
→ SetDark_mode = no
- If
Dark
is selected:
→ SetUser's Theme = Dark
→ SetDark_mode = yes
- If
System
is selected:
→ SetUser's Theme = System
→ Run this JavaScript to re-check the system theme:
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
bubble_fn_theme_change(isDark ? 'yes' : 'no');
How Does This Compare to Zeroqode’s Dark Mode Detector?
Zeroqode’s dark mode plugin is popular — but it lacks live detection. You need to manually run their action every time you want to check the system theme. That means if you want real-time responsiveness, you’d have to run a workflow on a loop, say every second — not ideal for performance or UX.
Editor
And that’s about it! With a few lines of JavaScript and Bubble logic, you’ve now got a system-aware theme engine that’s reactive, lightweight, and user-customizable.
Enjoy your fully responsive dark/light mode — perfect for those dedicated users who appreciate the extra polish!