Hi everyone, can someone tell me how I can change the color and background color of the Icons and the buttons? Itâs thermostat-card, HVAC modes.
Thank you very much in advance
Frank
Hi everyone, can someone tell me how I can change the color and background color of the Icons and the buttons? Itâs thermostat-card, HVAC modes.
Thank you very much in advance
Frank
Ask in the main card-mod thread, this one is for themes
Hi,
I am quite satisfied with my theme now. I have background colors change based on entity states and it works flawlessly.
BUT,
How can i keep my theme from conflicting with other themes? No matter which theme i select, my background mods still appear.
clear:
modes:
dark: {}
ha-card-border-width: '0px'
ha-card-border-radius: '33px'
ha-card-background: 'rgba(150, 150, 165, 0.1)'
mush-chip-height: '34px'
mush-title-padding: '24px 16px 16px'
mush-title-font-size: '20px'
bar-card-border-radius: '8px'
primary-color: 'rgba(189, 237, 142, 1.0)'
mdc-theme-surface: 'rgba(43, 53, 60, 1.0)'
ha-card-box-shadow: 'none'
mush-card-secondary-color: 'rgba(150, 150, 150, 1.0)'
mush-card-secondary-font-weight: '600'
# Fonts
primary-font-family: 'Roboto'
paper-font-common-base_-_font-family: "var(--primary-font-family)"
paper-font-common-code_-_font-family: "var(--primary-font-family)"
paper-font-body1_-_font-family: "var(--primary-font-family)"
paper-font-subhead_-_font-family: "var(--primary-font-family)"
paper-font-headline_-_font-family: "var(--primary-font-family)"
paper-font-caption_-_font-family: "var(--primary-font-family)"
paper-font-title_-_font-family: "var(--primary-font-family)"
ha-card-header-font-family: "var(--primary-font-family)"
# Colors
# Bubble Card variables test
bubble-border-radius: "8px"
bubble-main-background-color: "rgb(150,150,150)"
bubble-secondary-background-color: "rgb(1,1,1)"
bubble-pop-up-main-background-color: "rgba(1,1,1,0.5)"
bubble-accent-color: "rgb(1,1,1)"
bubble-icon-background-color: "rgb(5,8,1)"
bubble-select-list-width: "200px"
bubble-select-list-background-color: "rgb(1,1,1)"
# Background image
lovelace-background: 'center / cover no-repeat url("/local/media/misc/bg.jpg") fixed'
card-mod-theme: clear
card-mod-card: |
ha-card {
background: {% if is_state(config.entity, 'on') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
--bsc-slider-color: #f9d2b0; /* Customize the slider color */
--bsc-primary-text-color: black;
--bsc-icon-color: black;
{% elif is_state(config.entity, 'home') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
{% elif is_state(config.entity, 'open') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
{% elif is_state(config.entity, 'heating') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
{% elif is_state(config.entity, 'playing') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
{% endif %}
}
ha-card {
background: {% if config.entity.startswith('person.') and is_state(config.entity, 'home') %} rgba(150, 150, 165, 0.1);
--card-primary-color: white;
--bsc-background: rgba(150, 150, 165, 0.1);
--bsc-color: white;
{% endif %}
}
ha-card {
background: {% if config.entity.startswith('climate.') and is_state_attr(config.entity, 'hvac_action', 'heating') %} rgba(225, 225, 225, 1);
--card-primary-color: black;
--bsc-background: rgba(225, 225, 225, 1);
--bsc-color: black;
{% endif %}
}
stack-in-card {
--stack-in-card-background: rgba(255, 255, 255, 0.9); /* Adjust the background for the stack */
--stack-in-card-border-radius: 12px; /* Optional border radius */
--stack-in-card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Optional shadow */
--bsc-background: inherit; /* Inherit from the stack if needed */
--bsc-color: inherit;
--bsc-slider-color: inherit;
}
Hi! So far while using card-mod âinlineâ I was able to figure out most of the things using Ildarâs magnificent post!
Now I started to my stuff to themes (mainly for deduplication purposes) and seems like I still missing a couple of thingsâŚ
Question #1: I have a bunch of cards that shows batteries info:
type: entities
state_color: true
entities:
- entity: sensor....
name: ...
- entity: sensor....
name: ...
...
grid_options:
columns: 12
rows: auto
title: Phones/Tablets
card_mod:
style:
hui-sensor-entity-row:
$:
hui-generic-entity-row:
$: |
state-badge {
transform: rotate(90deg);
height: 32px;
line-height: 32px;
}
.: |
ha-card .card-header .name {
font-size: 20px;
line-height: 24px;
}
Using card-mod here to rotate icon and reduce margins. To move this to themes, I assigned class: my-batteries to the cards.
Reducing margins is easy in this case. In themes.yaml, I added:
card-mod-card-yaml: |
.: |
...
ha-card.my-batteries .card-header .name {
font-size: 20px;
line-height: 24px;
}
...
and it works!
But how to specify that icon rotation should only be applied to .my-batteries cardsâŚ
In themes.yaml, tried:
card-mod-card-yaml: |
...
.my-batteries: |
hui-sensor-entity-row: |
$: |
hui-generic-entity-row: |
$: |
state-badge {
transform: rotate(90deg);
height: 32px;
line-height: 32px;
}
...
but no luck.
Any Idea what do I do wrong?
Update on question #1: seems I found how to style non-shadow-root parts of whole card and its entitiesâŚ
Giving whole card has class .my-batteries and one of the entities - .my-battery,
I can write following:
style:
.: |
:host(.my-battery) {
color: blue;
}
...
style:
.: |
:host .my-batteries {
color: red;
}
To make whole cardâs text red and my-batteryâs entity - blue. But how can I get inside shadow-roots???
Tried this:
":host .my-batteries":
hui-sensor-entity-row:
$:
hui-generic-entity-row:
$: |
state-badge {
transform: rotate(90deg);
height: 32px;
line-height: 32px;
}
No luck
Question #2: I also have several tile cards I want to change icon color based on the value. I use template sensor to calculate and store color in the attribute so the card looks like this:
type: tile
entity: sensor.co2_max
grid_options:
columns: 3
rows: 2
vertical: true
hide_state: false
show_entity_picture: false
name: " "
card_mod:
style: |
ha-tile-icon {
--tile-color: {{ state_attr(config.entity, "zone_color") }};
}
Again as part of moving to theme, added a class to card and removed inline CSS:
type: tile
entity: sensor.co2_max
grid_options:
columns: 3
rows: 2
vertical: true
hide_state: false
show_entity_picture: false
name: " "
card_mod:
class: my-zone-color
adding them to theme.yaml:
card-mod-card-yaml: |
...
.my-zone-color ha-tile-icon {
--tile-color: {{ state_attr(config.entity, "zone_color") }};
}
...
Well, coloring works as expected, but started to get 100s of messages in the logs:
2025-02-26 16:16:03.673 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: 'dict object' has no attribute 'entity' when rendering 'ha-card.my-heading .container .content ha-icon-next {
display: none;
}
.my-zone-color ha-tile-icon {
--tile-color: {{ state_attr(config.entity, "zone_color") }};
}'
So it does seem card-mod tries to apply jinja template to each and every ha-card I have on the page, including static headers that does not have config.entity set at all!
Any ways to limit jinja template calculations only for class:my-zone-color cards?
as a heads-up: HA 2025.3 (now in beta) seems to have borked this option to scroll.
havent completely explored all options yet, but is seems there was a change card-mod does not yet support
Ive opened a discussion FR: add option to swipe/scroll view badges horizontally ¡ home-assistant/frontend ¡ Discussion #24415 ¡ GitHub to get the swipe option in CoreâŚ
havent been able to touch the hui-view-header yet, all other badges mods stil work though
Hi,
I have a simple mushroom card for the control of a garage.
I want the card to blink when state is opening or closing but I donât get it to work.
I tried with adding but this does not change anything.
--animation: blink 1s linear infinite;
@keyframes blink { 50% {opacity: 0;} }
Is anyone able to support? Addionally I want to have the german labels instead of the state names on the card. So in case of state open I want to show âoffenâ.
type: custom:mushroom-entity-card
entity: sensor.garage_tr_left_status
secondary_info: state
tap_action:
action: call-service
confirmation:
text: Wirklich ausfĂźhren?
service: switch.turn_on
service_data:
entity_id: switch.shellyplus2pm_10061cc9f634_switch_0
name: Garage links
primary_info: name
icon_color: white
card_mod:
style: |
ha-card {
text-align: left;
height: 70px !important;
{% set state=states('sensor.garage_tr_left_status') %}
{% if state == 'open' %}
--ha-card-background: red;
offen
{% elif state == 'opending' %}
--ha-card-background: orange;
{% elif state == 'closing' %}
--ha-card-background: orange;
--animation: blink 1s linear infinite;
@keyframes blink { 50% {opacity: 0;} }
{% elif state == 'closed' %}
--ha-card-background: green;
geschlossen
{% endif %}
}
Letâs say one wants to make all text of all cards red via card-mod theme. Easy:
...
card-mod-card-yaml: |
".": |
ha-card {
color: red;
}
...
Now, limit this only to cards with class âmy-classâ. No problem:
In card(s):
...
card-mod:
class: my-class
...
In theme:
card-mod-card-yaml: |
...
".": |
ha-card.my-class {
color: red;
}
...
Next level: make only names green. Requires interaction with shadow-roots, but still possible - for all cards it can be done by adding following in theme.yaml:
card-mod-card-yaml: |
...
hui-sensor-entity-row:
$:
hui-generic-entity-row:
$: |
.info.pointer {
color: green;
}
...
Now - real challenge: try to restrict that only to âmy-classâ cards.
Following:
card-mod-card-yaml: |
...
".my-class":
hui-sensor-entity-row:
$:
hui-generic-entity-row:
$: |
.info.pointer {
color: green;
}
...
doesnât work, probably because it tries to look for element having âmy-classâ among ha-card elementâs children and fails to find any, because it is ha-card itself has this class.
Also tried following selectors, but w/o any success:
".:is(.my-class)":
"..my-class": (note two dots here - try to say "'this' with class 'my-class'")
So, is there any way to achieve this?
To get a shadow root inside a particular class: described here:
main card-mid thread - 1st post - link at the bottom - themes - shadow root in a class
Somehow missed that⌠Shame on me!
In fact, also started to consider usage of variables, but it looks so cumbersome - was hoping it should be a better way.
Wonder is there any architectural limitation that prevents adding âroot{something}â-like selector (e.g. âroot.my-classâ) to the ââŚ-yamlâ entries?
BTW, here is another thing I did while tried to make it work. if both is true:
you can do this:
Card:
type: entities
entities:
- entity: ...
card_mod:
class: my-class
- entity: ...
card_mod:
class: my-class
- entity: ...
card_mod:
class: my-class
Theme:
card-mod-card-yaml: |
...
hui-sensor-entity-row.my-class:
$:
hui-generic-entity-row:
$: |
.info.pointer {
color: green;
}
...
But you can use config.entities[i].entity.
Wait, do you mean âiâ as a constant? Like: config.entities[0].entity?
Or is there still a way to have it updated for each entity?
Use it on âforâ.
Can hardly imaging how to apply this in themes. Any snippet?
No PC, no snippet. You said that you want to use some card-level style but cannot use âconfig.entityâ. Means - you need to analyze some entity: if true - then some style. So enumerate all entities inside a card (ie in config.entities) in âforâ and style.
Looking at card-mod.ts sources:
...
private async _connect() {
const styles = this._fixed_styles ?? {};
const styleChildren = {};
let thisStyle = "";
let hasChildren = false;
const parent = this.parentElement || this.parentNode;
this._debug("(Re)connecting", this);
// Go through each path in the styles
for (const [key, value] of Object.entries(styles)) {
if (key === ".") {
if (typeof value === "string") thisStyle = value;
else this._debug("Style of '.' must be a string: ", value);
} else {
hasChildren = true;
styleChildren[key] = this._style_child(key, value).catch((e) => {
if (e.message == "NoElements") {
if (this.debug) {
console.groupCollapsed("card-mod found no elements");
console.info(`Looked for ${key}`);
console.info(this);
console.groupEnd();
}
return;
}
throw e;
});
}
}
...
think it should be possible to add another condition in between.
Like this naive implementation for single class support:
// adding root element's class handling ("..{className}" notation)
else if (key.startsWith('..')) {
let className = key.substr(2, key.length-2);
const parent = this.parentElement || this.parentNode;
if (parent.classList.contains(className)) {
// root element contains class -> continue recursive magic for value
} else {
// root element does not contain class -> ignore value;
continue;
}
// end classes handling
Not quite yet understand how to trigger recursive magic continuation . Any help?
Seems like you may already have a solution, but you can also play with some advanced CSS features too. This doesnât work in every browser (yet - check compatibility of :host-context()
). The code below isnât specific to your situation, but shows the use of :host-context()
. It took me a few minutes to figure out how it worked, but basically itâs similar to :has()
where you can specify a selector that will select a shadow root where the selector matches.
So, in this example, I can style ha-icon
where, as a parent before the shadow root for ha-svg-icon
(the thing I need to change), it matches paper-tab.iron-selected
(the selected header tab on a dashboard), and then I can style the ha-svg-icon thatâs inside the shadow root.
card-mod-root-yaml: |
"ha-icon$": |
:host-context(paper-tab.iron-selected) ha-svg-icon{
fill:var(--theme-icon-header-color);
}
FYI, this lets me customize the fill colour for the icon in the selected header tab and ensures that when you change tabs, it changes the colour back to normal (if you didnât do this, it would permanently style the first selected tab and it would remain this colour even after changing tabs).
Nice! I like it much more than CSS variables hack.
Though being able to use classes directly is much-much more cleaner.
And it seems I nailed it after all !
Took slightly different approach than initially planned - now Iâm looping through styles dictionary separately to find any starting with ââŚâ.
For any key/value found:
So, basically, if I have this entry in themes.yaml
card-mod-row-yaml:
...
..my-class.my-class2:
hui-generic-entity-row:
$: |
.info.pointer {
font-size: 120%;
}
....
for entities with âclass: my-class my-class2â it becomes:
hui-generic-entity-row:
$: |
.info.pointer {
font-size: 120%;
}
for all other entities - it completely discarded.
Here is my code (put it after this._debug(â(Re)connectingâ, this); line):
// adding root element's class handling ("..{className1}.{className2}.{classNameN}" notation)
let parentEl = this.parentElement || (this.parentNode ? this.parentNode['host'] : null);
for (const [key, value] of Object.entries(styles)) {
if (key.startsWith('..')) {
delete styles[key];
if (parentEl) {
let classNames = key.substring(2, key.length).split('.');
if (classNames.every(cl => parentEl.classList.contains(cl))) {
// root element contains all classes -> merge value into styles
if (typeof value === "string")
this._debug("If style of '..' is a string - you can safely put it under '.': ", value);
// or we can do it ourselves:
// merge_deep(styles, {'.' : value});
else {
merge_deep(styles, value);
}
} else {
// root element does not contain all classes -> ignore value;
continue;
}
} else {
console.warn("Cannot find parent element!");
}
}
}
However, is this not parsing styles only once, so if the classes change dynamically, those styles arenât re-evaluated at all. Might not be an issue all the time, but if you do have something that toggles classes, the styles wouldnât change because the class piece isnât part of the rendered CSS rule itself.
True. Consider the main purpose of this change is to allow to move âstaticâ part of the CSSes from the cards to the theme to removing duplication in the first place.
Obviously, it is not intended to cover all the use-cases, especially such complicated as dynamic class chang. For those - different solution still might be needed.
Have you had any progress with this?