I've noticed that people on the internet ask how to hide the Salesforce dashboard's header, especially in the Experience Cloud.
We don't have much control, but could we use CSS to override the default styles? Yes, we can!
Salesforce Dashboard Challenge
As mentioned, we have limited control over the dashboard component, and its styles are isolated because Salesforce loads it within an iframe.
There is a workaround available.
I've published a post some time ago on how to load standard Salesforce dashboards inside Lightning Web Components.
It becomes convenient when working on custom UIs, whether for internal Lightning applications or in the Experience Cloud.
For example, I worked on a custom app for conducting strategy workshops that included a complex UI with various tabs, data tables, and they wanted to embed the dashboard directly into it.
Recently, I faced another use case where a business wanted to embed the default dashboard into Experience Cloud for their customer portal.
While you can embed the standard dashboard in the Lightning builder, the business only wanted to display the data, removing the dashboard header as well as the rest of the interactive elements.
They had hit a wall and were considering implementing a custom dashboard using LWC to render the data that they would've calculated themselves.
I researched the internet and found that there are many more similar unresolved cases.
Accessing the Salesforce Dashboard DOM
I had the idea to load the dashboard inside the LWC, as I did before, and inject styles using vanilla JavaScript.
The most important thing is that we need to access the DOM of the dashboard page.
Then, we can inject CSS or use JavaScript to override its default behavior.
First, let's create the dashboard LWC and load the iframe with the Dashboard App.
You can construct the dashboard URL by providing the dashboard and user IDs.
import { LightningElement, api } from "lwc";
import userId from "@salesforce/user/Id";
export default class Mc_dashboard extends LightningElement {
@api dashboardId;
get dashboardUrl() {
return `/desktopDashboards/dashboardApp.app?dashboardId=${this.dashboardId}&displayMode=view&networkId=000000000000000&userId=${userId}`;
}
}
Note: You should import and use the network ID for the Experience Cloud via
@salesforce/community/Id
as it affects the displayed data. Also, you can import base path via@salesforce/community/basePath
, but note that it includes/s
bit, but you only need the origin.
Then, load the dashboard in the component template.
<template>
<iframe
title="dashboard"
height="400px"
width="100%"
frameborder="0"
src="{dashboardUrl}"
spellcheck="false"
></iframe>
</template>
Finally, let's expose the dashboard ID to the app builder, so that admins can reuse it.
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>64.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>MC Dashboard</masterLabel>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__RecordPage</target>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__AppPage">
<property name="dashboardId" label="Dashboard Id" type="String" />
</targetConfig>
<targetConfig targets="lightningCommunity__Default">
<property name="dashboardId" label="Dashboard Id" type="String" />
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Alright, now you can render the dashboard component within the iframe.
Here is a good thing! Since we loaded the iframe within the LWC, it has direct access to its content document.
In other words, we have complete control over its DOM.
For instance, if I want to hide the dashboard's header, I can either modify the header element's style properties directly, attach the class, or inject the override styles.
Note: If you try to access the iframe and inject styles on the
connectedCallback
orrenderedCallback
lifecycle hooks, it won't work because the content document hasn't been loaded yet.
Instead, you can attach the onload
event handler to make sure the iframe's document is ready.
<template>
<iframe
title="dashboard"
height="400px"
width="100%"
frameborder="0"
src="{dashboardUrl}"
spellcheck="false"
onload="{handleLoad}"
></iframe>
</template>
I created and attached the handleLoad
function, which is invoked after the iframe finishes loading.
Here is the updated LWC implementation with the event handler function.
import { LightningElement, api } from "lwc";
import userId from "@salesforce/user/Id";
export default class Mc_dashboard extends LightningElement {
@api dashboardId;
get dashboardUrl() {
return `/desktopDashboards/dashboardApp.app?dashboardId=${this.dashboardId}&displayMode=view&networkId=000000000000000&userId=${userId}`;
}
handleLoad(e) {
const style = document.createElement("style");
style.innerText = `
.grid-layout-header {
display: none;
}
`;
e.currentTarget?.contentDocument.head.appendChild(style);
}
}
It does a straightforward job of creating a new style element with overwritten grid-layout-header
styles and appending it to the iframe's content document.
Conclusion
Using this approach, you can add whatever styles you want or directly interact with the dashboard elements.
It's a bit hacky and not an ideal solution, but that's not the first time we've had to devise a workaround on the platform. It definitely requires less effort than implementing the dashboards yourself.
I hope it helps you save time! Happy coding!

Nikita Verkhoshintcev
Senior Salesforce Technical Architect & Developer
I'm a senior Salesforce technical architect and developer, specializing in Experience Cloud, managed packages, and custom implementations with AWS and Heroku. I have extensive front-end engineering experience and have worked as an independent contractor since 2016. My goal is to build highly interactive, efficient, and reliable systems within the Salesforce platform. Typically, companies contact me when a complex implementation is required. I'm always open to collaboration, so please don't hesitate to reach out!