Salesforce users have been asking for it for years, and it’s finally here: Color Mode (Beta). Users can now toggle between Light, Dark, and System modes directly from their profile avatar.
While this is a massive win for user experience, it presents a unique challenge for third party apps within Salesforce. If your application runs inside an iframe—whether it’s hosted on Heroku or other platforms—it won’t automatically “see” the Salesforce theme change. If the Salesforce UI turns dark while your iframed app stays blindingly white, the user experience feels broken.
Because these external apps often don’t use SLDS 2.0 directly, you need a custom bridge to sync the themes. Here is how to detect Salesforce’s color scheme changes and pass that intelligence down to your application.
The Challenge: The “System” Settings Dilemma
Salesforce doesn’t just offer a “Dark” or “Light” switch; they offer a System mode. This means:
- Light Mode: Always light.
- Dark Mode: Always dark.
- System Mode: Follows the Operating System (macOS/Windows) settings.
To make your iframed app feel native, you need to listen for when the Salesforce setting changes and when the OS setting changes.
Step 1: Watching the Salesforce Body Class
Salesforce communicates the current theme by appending a specific class to the <body> tag of the Lightning Experience. The classes are:
- slds-color-scheme–light
- slds-color-scheme–dark
- slds-color-scheme—system
To detect this change in real-time, we use a MutationObserver. This allows your Lightning Web Component (LWC) to “watch” the body tag and react the moment a class is added or removed.
JavaScript
// Initialize the observer in your LWC or script
this.observer = new MutationObserver(() => this.handleChange());
this.observer.observe(document.body, {
attributes: true,
attributeFilter: ['class']
});
Step 2: Determining the Scheme
Inside your handleChange() function, you need to parse those classes. However, when the class is slds-color-scheme–system, you have to do a little extra work to figure out what “System” actually means at that moment.
This is where window.matchMedia comes to the rescue.
JavaScript
// Setup a listener for the OS-level color scheme
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
this.mediaQuery.addEventListener('change', () => this.handleChange());
handleChange() {
let scheme;
const bodyClassList = document.body.classList;
if (bodyClassList.contains('slds-color-scheme--light')) {
scheme = 'light';
} else if (bodyClassList.contains('slds-color-scheme--dark')) {
scheme = 'dark';
} else if (bodyClassList.contains('slds-color-scheme--system')) {
// If Salesforce says "System", check the browser/OS preference
scheme = this.mediaQuery.matches ? 'dark' : 'light';
}
if (scheme) {
this.updateIframe(scheme);
}
}Step 3: Communicating with the Iframe
Now that you’ve identified the correct mode, you simply need to tell your hosted app what to do. The most secure and efficient way is via postMessage.
JavaScript
updateIframe(scheme) {
const iframe = this.template.querySelector('iframe');
if (iframe) {
iframe.contentWindow.postMessage({
type: 'COLOR_SCHEME_CHANGE',
scheme: scheme
}, '*'); // In production, replace '*' with your actual app URL for security!
}
}
Wrapping Up
By combining a MutationObserver with window.matchMedia, you can ensure your application feels like a seamless part of the Salesforce ecosystem, regardless of which color mode the user prefers.
It’s these small attention-to-detail features that separate a good app from a great one.
Why Does It Matter To SharinPix ?
The look and feel of your Salesforce org is a simple yet significant way to affect adoption at your organization. SharinPix is a strong believer in making Salesforce more visual to increase overall usability and the efficiency of both field and back-office teams. That’s why we have 30+ lightning components to unlock any visual use case in Salesforce, from uploading and viewing pictures in a gallery to annotating a floor plan.
Check out our website for more details or swing by our Salesforce AgentExchange listing.

References: