Just want to share a hack to get badge icons instead for numbers.
Me myself and claude did this so be kind. Anyone who actually know javascript and css is more then welcome to correct it, but it works.
I added this as a resource in dahsboard. /local/navbar-badge-icons.js and the file in the www folder
// www/navbar-badge-icons.js
(function () {
// Global registry: routeIndex -> desired icon
window.__navbarBadgeIcons = window.__navbarBadgeIcons || {};
// This is the function you call from your YAML templates
window.setNavbarBadgeIcon = function (routeIndex, iconName) {
window.__navbarBadgeIcons[routeIndex] = iconName || null;
return ""; // so you can return the result directly in e.g. count:
};
function findNavbarCards(root, found = []) {
root.querySelectorAll("*").forEach((el) => {
if (el.localName === "navbar-card") found.push(el);
if (el.shadowRoot) findNavbarCards(el.shadowRoot, found);
});
return found;
}
function applyIcons(navbarCard) {
if (!navbarCard.shadowRoot) return;
const routes = navbarCard.shadowRoot.querySelectorAll(".route");
routes.forEach((route, index) => {
const badge = route.querySelector(".badge");
const desiredIcon = window.__navbarBadgeIcons[index];
if (!badge) return;
// No icon wanted for this route -> make sure any old icon is removed
if (!desiredIcon) {
const existing = badge.querySelector(".custom-badge-icon");
if (existing) {
existing.remove();
badge.style.fontSize = "";
}
return;
}
let iconEl = badge.querySelector(".custom-badge-icon");
if (!iconEl) {
badge.style.fontSize = "0";
badge.style.setProperty("width", "19px", "important");
badge.style.setProperty("height", "18px", "important");
badge.style.display = "flex";
badge.style.alignItems = "center";
badge.style.justifyContent = "center";
iconEl = document.createElement("ha-icon");
iconEl.className = "custom-badge-icon";
iconEl.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 16px;
height: 16px;
--mdc-icon-size: 16px;
`;
iconEl.style.setProperty("--icon-primary-color", "black", "important");
badge.appendChild(iconEl);
}
// Only update if the icon actually changed (e.g. lock -> lock-open)
if (iconEl.getAttribute("icon") !== desiredIcon) {
iconEl.setAttribute("icon", desiredIcon);
}
});
}
function scanAndApply() {
findNavbarCards(document.body).forEach((card) => {
applyIcons(card);
if (!card.__badgeIconObserver) {
const obs = new MutationObserver(() => applyIcons(card));
obs.observe(card.shadowRoot, { childList: true, subtree: true });
card.__badgeIconObserver = obs;
}
});
}
scanAndApply();
new MutationObserver(() => scanAndApply()).observe(document.body, {
childList: true,
subtree: true,
});
// Extra safety net: templates may run before the DOM has finished
// mutating, so we also run a quick follow-up check.
window.setNavbarBadgeIcon = new Proxy(window.setNavbarBadgeIcon, {
apply(target, thisArg, args) {
const result = target.apply(thisArg, args);
requestAnimationFrame(scanAndApply);
return result;
},
});
})();
And then this in the navbar card under routes->badge->count (I think you should be able to put it in “css styles” but i had issues with that.)
return window.setNavbarBadgeIcon(
3,
hass.states['sensor.garage_door_state']?.state === 'closed'
? 'mdi:garage'
: 'mdi:garage-open'
);
The number is the position of the route, in this case the 4th position.(0,1,2,3) and the second part is the icon you want.