How to remove sidebar and header from Webpage (iframe) card

Hi, I am fairly new to home assistant, and I am trying to tidy up the left menu bar by moving some of the items that would normally show up there into a combined dashboard. I created a new “Admin Utilities” dashboard, and have added multiple panel (1 card) views with a webpage iframe card that points to each item I would like to include. The problem that I am running into is that often the cards load the home assistant left sidebar and top header into the iframe itself, thereby showing a duplicate sidebar and header (see attached image).

For add-ons that use ingress such as Terminal & SSH, Z-Wave JS UI, etc. I orignally directed the iframe card to “/hassio/ingress/[add on]”, for example “/hassio/ingress/core_ssh”. This causes the duplicate sidebar and header issue. I eventually stumbled my way into finding that if I opened the Web UI for each add on, I could right click in my browser and select “This Frame” > “Show Only This Frame” to get a url that doesn’t include the Home Assistant sidebar or header. I can now direct the iframe card to a url like “/api/hassio_ingress/[ingress key]/” and I get a clean view of those add-ons.

The problem I am having is sidebar items that do not use ingress such as default Home Assistant items like History, Logbook, as well as custom items like HACS or Browser Mod. Creating a lovelace card that directs to “/logbook” or “/history” or “/hacs” or “/browser-mod” includes the sidebar and header.

I have tried using Kiosk Mode from HACS, and was unsuccessful. Kiosk Mode only seems to affect dashboards that I have created myself, not default panels or panels added through other means. So when I point a webpage card to my Music dashboard at “/dashboard-music/0?kiosk” then the sidebar and header are hidden. When I instead point to “/logbook?kiosk” the sidebar and header are back.

I have also tried using card-mod to hide the sidebar and header elements, but to say that I am way out of my element with CSS is beyond an understatement. By playing around with my browser’s inspector, I found that setting ha-sidebar to “display: none;” makes the sidebar disappear but leaves a space on the left side where the sidebar would have been. If instead under home-assistant-main I set --mdc-drawer-width to 0 instead of its default value of “calc(256px + env(safe-area-inset-left))” seems to hide the sidebar how I would like and expands the rest of the page to fill as I would expect. That’s great except I have no idea how to use card-mod to modify --mdc-drawer-width, everything I have tried hasn’t taken effect as I would expect when I add it to the webpage card. I also feel like I am very likely barking up the wrong tree and that there might be some other way to get a clean view of these panels, but I don’t know if there is some equivalent to “/api/hassio_ingress/[key]” but for these other views.

I’m currently running Home Assistant on an old x86 laptop.

For anyone who might stumble upon this in the future, I still haven’t found a solution like I would prefer, but here’s a few workarounds that I have implemented.

I’ve created a dashboard called “Home Assistant Utilities” where I have put most of the admin things that I want occasional access to but don’t need cluttering up the sidebar. The first view on this dashboard has a stack of buttons to navigate elsewhere fairly easily.

For Logbook, History, HACS, and Browser Mod, I created buttons that navigate to the appropriate page (e.g. the Logbook button navigates to “/logbook”). This opens up the logbook page fullscreen, rather than as an iframe on the utilities dashboard. The biggest downside is that I lose a back button or top menu bar to navigate between view easily. For example, to get to logbook, I click Home Assistant Utilities > Logbook. Then to navigate from that screen to History I have to click first on Home Assistant Utilities again, and then on History. It’s more clicking than I would prefer, but it’s better than sorting through a long list on the sidebar every time.

For the Add-ons, I created a view as I previously mentioned, using “/api/hassio_ingress/[ingress key]/”, and then added a button on the first view that navigates to that view. The only downside that I have run into is that when opening one of these views in a new browser, I need to do an initial authentication, otherwise I get an error like “401: Unauthorized”. My workaround is to create a hold-action that navigates to “/hassio/addon/[add-on]” for the appropriate add-on. So for example, Terminal navigates to “/hassio/addon/core_ssh/info”. From that page, I can click “Open Web UI” to authenticate the first time. After that, the view I created works just fine. It’s a little inconvenient the first time, but it has been very helpful as I have been building out my Z-Wave network to be able to pull up the view within the dashboard rather than navigating to the add-on info page every time. I know I could show Z-Wave JS UI in my sidebar to theoretically be even faster, but I found it was overall slower navigating around when I had a cluttered sidebar, especially once I had enough menu items that I would have to scroll within the sidebar to see all the menu items. This current iteration of my setup fits in both my browser and on mobile without having to scroll to see all the menu items.

Finally, to clean up the sidebar, I used Browser Mod to create a Sidebar Order on a per-user basis that automatically hides all of the dashboards I don’t want.

Here’s a screenshot of my current setup:

I’m still open to making further changes if anyone has solutions to either my initial dream for this setup that fixes the iframe issues, or if there’s an easy fix to the occasional authentication issue I run into. I mostly wanted to provide some ideas for anyone who might stumble upon this in the future looking to set up their Home Assistant in a similar way.

2 Likes

I might be late here but I finally figured out a way to do this which is inspired by Kiosk mode. What I ended up doing is making my own general purpose Javascript module which functions a lot like Kiosk mode but is pre-loaded for any internal URL not only in dashboards.

Here’s what I did.

  1. Create a script and placed in the www directory (/config/www/ui-tweaks.js)
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);

// Function to parse parameter from URL
function getParameter(param) {
    if (urlParams.has(param)) {
        if (urlParams.get(param).length === 0) return true;
        return Boolean(eval(urlParams.get(param)));
    } else return false
}

const ha_main = document.body.querySelector('home-assistant').shadowRoot
                    .querySelector('home-assistant-main').shadowRoot

// Hide sidebar
if (getParameter('hide_sidebar')) {
    // ha_main.querySelector('ha-sidebar').remove()
    ha_main.querySelector('ha-drawer').shadowRoot.querySelector('.mdc-drawer').remove();
    ha_main.querySelector('ha-drawer').shadowRoot.querySelector('.mdc-drawer-app-content').style.paddingLeft = '0px';
}
  1. Add the script as a resource
  • Settings → Dashboards → Menu (three dots in the top right corner) → Resources
  • Add Resource
  • Set URL to /local/ui-tweaks.js and resource type to Javascript Module
  1. Reload the page (probably need a hard reload)

Now when you add an iframe, add ?hide_sidebar to the end of the URL.

Enjoy!

1 Like

Hello. I tried using your script/method to hide the sidebar and it is not working for me. Are you still using it?
My HA is fully up to date.

I tried it on a couple of iframes such as:
https://ha.mydomain.com/hassio/ingress/d5369777_music_assistant?hide_sidebar
But it is still showing the sidebar in the iframe.

Yes, I’m still using it and it’s working so far. Is there any blocker installed in your browser that blocks Javascript? Can you check the browser’s dev console for any obvious errors (usually F12 and then select the console tab)? You could also check a different browser just to be sure nothing is blocked or incompatible. Let me know if you find something.

Hi thanks for responding. I found this message in the dev console:

Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
(anonymous)	@	d5369777_music_assistant?hide_sidebar:1

I created the javascript file using the built in file editor.
Could this be the problem?

That shouldn’t be a problem. Could you try to use an internal URL in your iframe instead of the full URL, like

/hassio/ingress/d5369777_music_assistant?hide_sidebar

Unfortunately that did not work either.
I was just reading something possibly related and the question of a proxy came up.
I am using Caddy reverse proxy running on opnsense in front of my HA server.
Maybe this is breaking the MIME type somehow?

Based on what I’m seeing online, It might be having trouble finding the script and it’s returning a 404 error. Are you sure it’s pointing to the right path? You can check by appending your module’s URL (/local/ui-tweaks.js in my case) to your domain

https://ha.mydomain.com/local/ui-tweaks.js

If that returns an error that’s your issue.

Yes appending the url shows the content of the script so that seems to be working. I also just checked my registry entry for .js under hkey_classes_root to be sure there was no modification there.

I have found posts concerning Caddy and MIME types so it could be related.
I am not an expert on Caddy by any means so it’s possible I have something configured wrong. I’ve been using it like this for a while but just recently decided to reconfigure my dashboards and ran into this issue today.

I will try to post back with any updates or solutions.

Thanks again.

Okay I realized I should just try bypassing Caddy to test if it was the issue or not.
It still is not working but I’m also not getting the message about the mime type. I’ve tried on chrome and firefox and in private browsers.

I do see this message in an incognito chrome session (logged in from my HA’s internal LAN address)

An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
d5369777_music_assistant?hide_sidebar

Also this is an http connection. Would that error or using http cause an issue?

This is my /local/ui-tweaks.js file (Should be the same as what you posted):

const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);

// Function to parse parameter from URL
function getParameter(param) {
    if (urlParams.has(param)) {
        if (urlParams.get(param).length === 0) return true;
        return Boolean(eval(urlParams.get(param)));
    } else return false
}

const ha_main = document.body.querySelector('home-assistant').shadowRoot
                    .querySelector('home-assistant-main').shadowRoot

// Hide sidebar
if (getParameter('hide_sidebar')) {
    // ha_main.querySelector('ha-sidebar').remove()
    ha_main.querySelector('ha-drawer').shadowRoot.querySelector('.mdc-drawer').remove();
    ha_main.querySelector('ha-drawer').shadowRoot.querySelector('.mdc-drawer-app-content').style.paddingLeft = '0px';
}

I have restarted home assistant and also force reloaded the browser pages.
Not sure what I’m missing

EDIT:
I just realized neither browser is actually showing the iframe in HTTP mode.
I’ll have to see if I can configure it with https on the local lan

1 Like

Okay I finally got a cert set up for my internal address and was able to access the page. Unfortunately I’m still getting the sidebar.

I had a lot of errors that all seemed to stem from UI-Lovelace-Minimalist that I had installed at one point.
I’ve completely removed it now and am getting no errors in the console at all but still seeing the sidebar.

For some reason it just doesn’t seem to be doing anything.
I reviewed the steps you outlined again and I’m pretty sure I’ve followed them exactly.

Can I ask which page you are using in an iframe? Maybe I could try replicating it to see if it works for me.

After more research I found this addon which seems to be working for me to resolve my iframe issues:

I found that the Ingress webpage card I had linked would not work the HACS and Browser Mod pages so I tried your tweak instead and it seems to be working well.
Thanks so much for sharing!

I also came here since i wanted to remove top and side bars. What I like about the proposed solution is that it works on demand. Whichever client adds a request parameter will not see that bar. Of course it is no security, but if looks matter it is perfect.

Since I also wanted to hide the top bar I modified the script by adding

// Hide top bar
if (getParameter('hide_top_bar')) {
 var top = ha_main.querySelector('ha-drawer partial-panel-resolver ha-panel-lovelace').shadowRoot.querySelector('hui-root').shadowRoot.querySelector('div div');   
 top.remove();                             
}

You can see from the clumsy path that I hardcoded the lovelace structure. This definitely needs to be improvemed, but such a feature should definitely go into the base homeassistant distribution.