It would be great to have a per-device toggle to enable or disable interface animations. This would be especially useful for devices with limited processing power, such as the Shelly Wall Display. Disabling transition animations—like those used when switching dashboards—could significantly improve performance and user experience on such hardware.
Hello sjurske,
This appears to be a Frontend Related Feature Request as it is asking for changes to Frontend Menus, Dashboards, Cards, Sections, or other Frontend Feature.
These Feature Requests are handled in a different system, and will not be seen by the right people if posted in the HA forums.
Please add your Feature Request into GitHub here:
home-assistant/frontend Other Feature Requests · Discussions · GitHub.
See more info about Feature Requests HERE
This already exists as a web accessibility standard, it’s called prefers-reduced-motion.
It is set either by your browser or OS, and when that flag is set, we disable a bunch of animations. You can check if you can leverage this.
Is there any similar setting to disable even more effects?
I.e. I would like to disable button’s background color change when it’s clicked or mouse hovers over the button.
For anyone interested in a super hacky solution, after spending a few hours with Claude yesterday, I managed to disable ripple animations on my HA kiosk display (while keeping them on on PC) using JS injection.
While this works, I bet there must be a cleaner way to do it, e.g. with card_mod, but I haven’t found a working solution.
In configuration.yaml, add extra_module_url:
frontend:
themes: !include_dir_merge_named themes
extra_module_url:
- /local/disable_ripple.js
And put this disable_ripple.js file into the config/www folder:
const isKiosk = /CrOS/.test(navigator.userAgent);
if (isKiosk) {
const sheet = new CSSStyleSheet();
sheet.replaceSync('ha-ripple { display: none !important; }');
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
function adoptIntoShadowRoots(root) {
root.querySelectorAll('*').forEach(el => {
if (el.shadowRoot) {
el.shadowRoot.adoptedStyleSheets = [...el.shadowRoot.adoptedStyleSheets, sheet];
adoptIntoShadowRoots(el.shadowRoot);
}
});
}
let debounceTimer;
function debouncedAdopt() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => adoptIntoShadowRoots(document), 300);
}
const observer = new MutationObserver(debouncedAdopt);
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(() => adoptIntoShadowRoots(document), 1000);
}