🔹 Card-mod - Add css styles to any lovelace card

Fixed it myself with

type: custom:mod-card
card_mod:
  style:
    $: |
      :host {
        height: 100%;
      }
    state-switch $: |
      #root {
        height: 100%;
      }
      #root > .visible > mini-graph-card {
        transform: none;
      }

Here could be a confusion for a person who finds this post.

There are two parts in your code:
– fixing a height (your issue);
– fixing a glitch with state-switch (your issue on Github).

These are unrelated things. The “transform: none” part is not related to the “height issue”.

Solution for “state-switch issue” was provided here.

Example of “if … else if … else …”

What is “OFF”? Means - the “media_player” is “unavailable”?
If yes - then the color is greyish (in a default light theme), then a different selector (not “background.no-image”) must be used.

Styling images in Logbook:

Once I posted a way of styling Logbook card.
Basically I was interested in square images for “entity_picture”.
Also, there was an issue with a tight placement (which I had to fix by card-mod) but that was solved.

That way has limitations:
– card-mod could not be applied to a “big” Logbook page (even in card-mod-theme);
– also it does not work inside “config-template-card” (yes, I do have plenty of “logbook” cards inside “config-template-card” with adjustable “hours_to_show”).

There is a way of defining a style for all logbooks - at least for square images.
The initial idea was proposed by @kulmegil in this post related to Map card.
Place this js code into “www” folder (or better create a special folder) and then add as a frontend module:

customElements.whenDefined('ha-logbook-renderer').then(() => {
    const LogbookBadge = customElements.get('ha-logbook-renderer');
    const { html, css } = LogbookBadge.prototype;
    
    // defined added style
    const newStyle = css`
    .icon-message state-badge {border-radius: 10%;}`;
    
    const newStyles = [].concat(LogbookBadge.styles, newStyle);
    Object.defineProperty(LogbookBadge, 'styles',        {value: newStyles, configurable: true, enumerable: false});
    Object.defineProperty(LogbookBadge, 'elementStyles', {value: newStyles, configurable: true, enumerable: false});
  });

image

For the “big” Logbook page the style works too:

The solution seems to work fine in Win+Chrome, iOS Companion App.
Anyway, need some more time for testing (is the style stable, is CPU usage same, …).


More styles

2 Likes

Could you guys help me? Or point me a way?

I’m using picture-elements and I would like the background to be 80% the size of the ha-card. I tested some ways that I found here but none worked.

This is what I have so far:

type: picture-elements
image: /local/img/tablet/home.png
style: |
 
   hui-image:
     $: |
       #image {width: 30%; margin: auto; }

    ha-card {...}

   }
elements:

I tested some variables like “img” or “image” but without success.

Thanks in advance.

Does anyone know if it’s possible or have tips in styling slider-entity-row to look like mushroom-cards sliders?

Turn this:

Into this:

W/o checking other things - this code is wrong in part of syntax.
Check other examples in the thread “accessing shadowRoot + ha-card”.
Also , you cannot use # for comments inside strings.

Slowly making progress. I got the knob to disappear with this:

card_mod:
  style:
    ha-slider:
      $:
        .: |
          .slider-knob-inner {
            opacity: 0%;
          }

And the height of the slider to change with this:

card_mod:
  style: |
    :host {
      --paper-slider-height: 42px;
    }  

I’m having trouble combining the two however.

I’ve now combined the two and extended the slider to the edges of the card.
Next goal is to round the corners on the slider. If I use inspect element to add border-radius: 12px to the sliderBar property it only works when I disable the padding property.

With padding 15px top and bottom and border-radius 12px:
chrome_4iSIBUSTmk
With padding 0px and border-radius 12px:
chrome_QTVia8Z1lx

Any tips on getting around this problem?

Another issue is that once I set the slider to 0% the first part disappears:

Slider at 1%:
chrome_KV8q6osg8X
Slider at 0%:
chrome_yZ47DvIb0w

This is the current code:

    card_mod:
      style:
        .: |
          :host {
            --paper-slider-height: 42px
          }
        ha-slider:
          $:
            .: |
              .slider-knob-inner {
                opacity: 0%;
              }
              div#sliderContainer {
                  margin-left: 0;
                  margin-right: 0;                                                
              }
            paper-progress:
              $: |
                #progressContainer {
                  background: red;
                }

Solved pretty much everything, the only thing left is to adjust the padding so that it matches mushroom-cards perfectly. To do so I have to add “padding: ‘13px 12px’” to the states div inside ha-card, but I’m having troubles doing so. I’ve found some old posts but I guess the syntax is different nowadays since I couldn’t get their snippets to work.

EDIT:

Got it working, I had to apply the padding styling to the whole card and not the entity. Here’s the final code and result, top is mushroom-card light card slider set to adjust brightness, bottom is two slider-entity-row sliders, one to control the light warm_white channel and one to control the cold_white channel:

chrome_W86Ego5171

Everything matches, altho the scrubbing on the mushroom card is much smoother, I assume because slider-entity-row only has 255 “steps”. Here you can find the code for this card:

type: custom:stack-in-card
cards:
  - type: custom:mushroom-light-card
    entity: light.livingroom
    use_light_color: true
    show_brightness_control: true
    show_color_temp_control: false
    show_color_control: false
    name: Living Room
  - type: custom:stack-in-card
    mode: vertical
    cards:
      - type: entities
        entities:
          - type: custom:slider-entity-row
            toggle: false
            hide_state: true
            full_row: true
            entity: light.livingroom
            attribute: warm_white
            card_mod:
              style:
                .: |
                  :host {
                    --paper-slider-height: 42px;
                    --paper-slider-active-color: {{ '#ffcd97' if config.attribute == 'warm_white' else '#99acff' }};
                    --paper-slider-container-color: {{ '#5A4835' if config.attribute == 'warm_white' else '#363c59' }};
                  }
                ha-slider:
                  $:
                    .: |
                      .slider-knob-inner {
                        display: none;
                      }
                      div#sliderContainer {
                          margin-left: 0;
                          margin-right: 0;                                                
                      }
                      .bar-container {
                          left: 0px !important;
                          top: 15px;
                      }
                    paper-progress:
                      .: |
                        #sliderBar {
                          padding: 0px !important;
                          border-radius: 12px;
                        }
        card_mod:
          style: |
            div#states {
              padding: 13px 12px;
            }
      - type: entities
        entities:
          - type: custom:slider-entity-row
            toggle: false
            hide_state: true
            full_row: true
            entity: light.livingroom
            attribute: cold_white
            card_mod:
              style:
                .: |
                  :host {
                    --paper-slider-height: 42px;
                    --paper-slider-active-color: {{ '#ffcd97' if config.attribute == 'warm_white' else '#99acff' }};
                    --paper-slider-container-color: {{ '#5A4835' if config.attribute == 'warm_white' else '#363c59' }};
                  }
                ha-slider:
                  $:
                    .: |
                      .slider-knob-inner {
                        display: none;
                      }
                      div#sliderContainer {
                          margin-left: 0;
                          margin-right: 0;                                                
                      }
                      .bar-container {
                          left: 0px !important;
                          top: 15px;
                      }
                    paper-progress:
                      .: |
                        #sliderBar {
                          padding: 0px !important;
                          border-radius: 12px;
                        }
        card_mod:
          style: |
            div#states {
              padding: 13px 12px;
            }

2 Likes

Nice mod.
Check this version, it has a “standard” height and a bit more “traditional” syntax.
BTW, the style may be applied to “slider-entity-row” & conventional slider.

type: entities
entities:
  - sun.sun
  - sun.sun
  - entity: input_number.test_level_1
    card_mod: &ref_0
      style:
        ha-slider $: |
          div#sliderKnob {
            height: 32px;
          }
          .slider-knob-inner {
            display: none;
          }
          div#sliderContainer {
            margin: 0px;                                                
          }
          .bar-container {
            left: 0px !important;
          }
          paper-progress {
            padding: 0px !important;
            border-radius: 12px;
            --paper-progress-height: 32px !important;
          }
        .: |
          :host {
            --paper-slider-active-color: lightgreen;
            --paper-slider-container-color: darkgreen;
          }
  - sun.sun
  - sun.sun
  - type: custom:slider-entity-row
    entity: input_number.test_level_1
    hide_state: true
    full_row: true
    card_mod: *ref_0

image

Note that this code:
--paper-slider-active-color: {{ '#ffcd97' if config.attribute == 'warm_white' else '#99acff' }};
does not update a color real-time - only after releasing a mouse input.


A bit modified version with a border:
ы1

Code
    card_mod:
      style:
        ha-slider $: |
          div#sliderKnob {
            height: 30px;
          }
          .slider-knob-inner {
            display: none;
          }
          div#sliderContainer {
            margin: 0px;                                                
          }
          .bar-container {
            left: 0px !important;
          }
          paper-progress {
            padding: 0px !important;
            border-radius: 12px;
            --paper-progress-height: 30px !important;
            width: unset !important;
            border: 1px solid darkgreen;
          }
        .: |
          :host {
            --paper-slider-active-color: lightgreen;
            --paper-slider-container-color: darkgreen;
          }

A variant with a knob:
12

Code
          div#sliderKnob {
            height: 30px;
            width: 8px;
            margin-left: -4px;
            background: var(--card-background-color);
            border: 1px solid var(--secondary-text-color);
          }
8 Likes

How to style map markers in Map card:

Initially the styling was discussed here, here, some other posts later.
Unfortunately, styles were not stable.

Solution was proposed on GitHub.
Author - @kulmegil.
Works in Map card & on a Map page.

image

Place this js code into “www” folder (or better create a special folder) and then add as a frontend module:

customElements.whenDefined('ha-entity-marker').then(() => {
    const EntityMarker = customElements.get('ha-entity-marker');
    const { html, css } = EntityMarker.prototype;
    
    // defined added style
    const newStyle = css`
    .marker {
      border: none !important;
      background-color: transparent !important;}`;
    
    const newStyles = [].concat(EntityMarker.styles, newStyle);
    Object.defineProperty(EntityMarker, 'styles',        {value: newStyles, configurable: true, enumerable: false});
    Object.defineProperty(EntityMarker, 'elementStyles', {value: newStyles, configurable: true, enumerable: false});
  });

Similarly it is possible to create “square avatars” - add this style:

border-radius: 10%;

image


Update 31.01.23:
The styling above provides a “square & transparent” marker - which is great for entities WITH “entity_picture” defined.
But what if it is NOT defined? Then we’ll see smth like this:
изображение
i.e. the marker now is presented as a label only - which is not great.

This updated js-file provides styles ONLY for entities with “entity_picture” defined:
изображение
The js code:

customElements.whenDefined('ha-entity-marker').then(() => {
    const EntityMarker = customElements.get('ha-entity-marker');
    const { html, css } = EntityMarker.prototype;
    
    // defined added style
    const newStyle = css`
    .marker:has(.entity-picture) {
      border: none !important;
      border-radius: 10%;
      background-color: transparent !important;}`;
    
    const newStyles = [].concat(EntityMarker.styles, newStyle);
    // The LitElement class has already been finalized, but hopefully not yet instantiated
    // guess I'll just do it the hard way
    Object.defineProperty(EntityMarker, 'styles',        {value: newStyles, configurable: true, enumerable: false});
    Object.defineProperty(EntityMarker, 'elementStyles', {value: newStyles, configurable: true, enumerable: false});
  });

Note that “.marker:has(.entity-picture)” part.


More styles

3 Likes

Conditional styling for different clients:

Assume you have a Windows desktop, iPhone & iPad.
In some cases we need to specify different styles for different clients.

Here is how to differentiate iOS client & not-iOS client:
place a selector with a style into a condition to specify a style for iOS clients:

        @supports (-webkit-touch-callout: none) {
          selector {
            ...
          }
        }

The example below contains 3 rows:
– styled for all clients;
– styled for iOS clients;
– styled for not iOS clients.

Code
type: entities
entities:
  - entity: sun.sun
    name: everywhere
    card_mod:
      style: |
        :host {color: red}
  - entity: sun.sun
    name: iOS clients
    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          :host {color: red;}
        }
  - entity: sun.sun
    name: not iOS clients
    card_mod:
      style: |
        @supports not (-webkit-touch-callout: none) {
          :host {color: red;}
        }

Screenshots are taken on a Windows desktop.
image


If a style includes a "shadowRoot" - need to place that conditions in every place.
Consider this style:

type: entities
entities:
  - entity: sun.sun
    name: Colored name & value
    style:
      hui-generic-entity-row $: |
        .info.pointer.text-content {
          color: orange;
        }
        .text-content:not(.info) {
          color: red;
        } 
      .: |
        :host {
          --paper-item-icon-color: cyan;
        }

image

Here is how to render it:

    card_mod:
      style:
        hui-generic-entity-row $: |
          @supports (-webkit-touch-callout: none) {
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info) {
              color: red;
            }
          }        
        .: |
          @supports (-webkit-touch-callout: none) {
            :host {
              --paper-item-icon-color: cyan;
            }
          }

A bit cumbersome; unfortunately, we cannot place the whole style into one condition:

    card_mod:
      style: |
        @supports not (-webkit-touch-callout: none) {
          hui-generic-entity-row $: |
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info){
              color: red;
            }
          .: |
            :host {
              --paper-item-icon-color: cyan;
            }
        }

An whole example:
image

Code
type: entities
entities:
  - entity: sun.sun
    name: everywhere
    card_mod:
      style:
        hui-generic-entity-row $: |
          .info.pointer.text-content {
            color: orange;
          }
          .text-content:not(.info){
            color: red;
          }
        .: |
          :host {
            --paper-item-icon-color: cyan;
          }
  - entity: sun.sun
    name: wrong syntax
    card_mod:
      style: |
        @supports not (-webkit-touch-callout: none) {
          hui-generic-entity-row $: |
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info){
              color: red;
            }
          .: |
            :host {
              --paper-item-icon-color: cyan;
            }
        }
  - entity: sun.sun
    name: text & icon - iOS
    card_mod:
      style:
        hui-generic-entity-row $: |
          @supports (-webkit-touch-callout: none) {
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info) {
              color: red;
            }
          }        
        .: |
          @supports (-webkit-touch-callout: none) {
            :host {
              --paper-item-icon-color: cyan;
            }
          }
  - entity: sun.sun
    name: text & icon - not iOS
    card_mod:
      style:
        hui-generic-entity-row $: |
          @supports not (-webkit-touch-callout: none) {
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info) {
              color: red;
            }
          }        
        .: |
          @supports not (-webkit-touch-callout: none) {
            :host {
              --paper-item-icon-color: cyan;
            }
          }
  - entity: sun.sun
    name: text - not iOS, icon - iOS
    card_mod:
      style:
        hui-generic-entity-row $: |
          @supports not (-webkit-touch-callout: none) {
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info) {
              color: red;
            }
          }        
        .: |
          @supports (-webkit-touch-callout: none) {
            :host {
              --paper-item-icon-color: cyan;
            }
          }
  - entity: sun.sun
    name: text - iOS, icon - not iOS
    card_mod:
      style:
        hui-generic-entity-row $: |
          @supports (-webkit-touch-callout: none) {
            .info.pointer.text-content {
              color: orange;
            }
            .text-content:not(.info) {
              color: red;
            }
          }        
        .: |
          @supports not (-webkit-touch-callout: none) {
            :host {
              --paper-item-icon-color: cyan;
            }
          }

Next point is - how to differentiate iPhone & iPad?
A desktop with 4K display & smaller panel 1920x1080?

Use "@media" conditions for different viewports & screen orientations.

Assume that besides Windows clients we have 3 iOS devices - iPad Air 2, iPhone 5s, iPhone 6 (please do not tell me that they are ancient - I do know it; you wanna fix it - buy me a coffee).
And we need 5 styles for these devices - and these styles must work for these devices only.
Means - we need to define rules for each device.

This code works on a Windows client with 1920x1080 display (fullscreen or less):

    card_mod:
      style: |
        @supports not (-webkit-touch-callout: none) {
          @media (max-width: 1920px) {
            :host { color: red; }
          }
        }

The code for a Windows client with 4K display (fullscreen or less):

    card_mod:
      style: |
        @supports not (-webkit-touch-callout: none) {
          @media (min-width: 1921px) and (max-width: 3840px) {
            :host { color: red; }
          }
        }

This code for iPad Air 2 (1536x2048) for different orientations:

    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: portrait) and (min-width: 768px) {
            :host { color: red; }
          }
        }
    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: landscape) and (min-width: 1024px) {
            :host { color: red; }
          }
        }

This code for iPhone 5S (640x1136) for different orientations:

    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: portrait) and (max-width: 320px) {
            :host { color: red; }
          }
        }
    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: landscape) and (max-width: 568px) {
            :host { color: red; }
          }
        }

This code for iPhone 6 (750x1334) for different orientations:

    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: portrait) and (min-width: 321px) and (max-width: 375px) {
            :host { color: red; }
          }
        }
    card_mod:
      style: |
        @supports (-webkit-touch-callout: none) {
          @media (orientation: landscape) and (min-width: 569px) and (max-width: 667px) {
            :host { color: red; }
          }
        }

Values for these "min-width" & "max-width" for iOS devices are set dependingly on “viewport sizes” which may be found here.
Have no idea how these “viewport sizes” are defined; why for iPad it is “768x1024” for “1536x2048” resolution and for iPhone it is “320x568” for “640x1136” (twice less) - is a riddle for me.
Some info may be googled (for example, here).

Another issue is “scaling in iOS Companion App”. My observations tell me that for a correct handling that "@media" conditions the scaling must be “100%”.
I myself usually use “50%” in Companion App for iPad; as for iPhone - do not use it, the App is too slow / too buggy (much more buggy than the App for iPad). So, with “50%” I observed that conditions not working…

I am using a combination of horizontal and vertical stack cards to give me the following:
image
I would like the borders between these elements to be smaller so they look connected, currently the “Select media device” looks like another separate element in my dashboard. Is there a way of doing this (I know css fairly well but can’t target the margin elements I need). Here’s my yaml for this:

type: vertical-stack
cards:
  - type: custom:button-card
    color_type: card
    color: rgb(0, 0, 164)
    margin: 0
    card_mod: null
    name: Select media device
  - type: horizontal-stack
    cards:
      - type: custom:button-card
        entity: input_select.media_device
        color_type: card
        color: rgb(0, 0, 164)
        styles:
          card:
            - height: 100%
        show_entity_picture: true
        show_name: false
        entity_picture: /local/images/WestWing.jpg
        state:
          - value: West wing Sonos
            entity_picture: /local/images/WestWingSelected.jpg
        tap_action:
          action: call-service
          service: input_select.select_option
          service_data:
            option: West wing Sonos
            entity_id: input_select.media_device
        hold_action:
          action: none
      - type: custom:button-card
        entity: input_select.media_device
        show_entity_picture: true
        color_type: card
        color: rgb(0, 0, 164)
        show_name: false
        entity_picture: /local/images/SonosBeam.jpg
        state:
          - value: Sonos beam
            entity_picture: /local/images/SonosBeamSelected.png
        tap_action:
          action: call-service
          service: input_select.select_option
          service_data:
            option: Sonos beam
            entity_id: input_select.media_device
        hold_action:
          action: none
      - type: custom:button-card
        entity: input_select.media_device
        show_entity_picture: true
        color_type: card
        color: rgb(0, 0, 164)
        show_name: false
        entity_picture: /local/images/google-home.png
        state:
          - value: Study speaker
            entity_picture: /local/images/google-home-selected.png
        tap_action:
          action: call-service
          service: input_select.select_option
          service_data:
            option: Study speaker
            entity_id: input_select.media_device
        hold_action:
          action: none

Try with “stack in card” (replaces vertical, horizontal card), it’s available in HACS. With it i made similar without any borders.

1 Like

Thanks. That seems to have worked.

1 Like

I’m currently building out my dashboard and when using ‘card-mod’ it does an annoying refresh / flash on the initial load of each tab.

Anyone know how I can get rid of this?

Demonstration:

ezgif-1-b0d97a1b8e

Code used in demo:

type: custom:mod-card
style: |
  ha-card {
    padding: 0px 30px 0px 30px!important;
  }
card:
  type: vertical-stack
  cards:
    - type: horizontal-stack
      cards:
        - type: custom:mod-card
          card:
            type: custom:mushroom-title-card
            title: Entertainment
          card_mod:
            style:
              mushroom-title-card$: |
                .header {
                  --title-padding: 23px 0px 40px;
                  letter-spacing: -0.12vw!important;
                }
                .title {
                  font-size: 35px!important;
                  font-weight: 520!important;
        - type: custom:mushroom-chips-card
          chips:
            - type: entity
              entity: sensor.bathroom_temperature
              tap_action:
                action: none
              hold_action:
                action: none
              double_tap_action:
                action: none
          alignment: end
          style: |
            .chip-container {
                padding-top: 0px;
                padding-right: 0px;
              }
            :host {
                --chip-background: none!important;
    - type: horizontal-stack
      cards:
        - type: custom:mushroom-light-card
          entity: light.bedside_lamps

uhm, feels silly but I can no longer find a way to widen the glance card canvas, without overflowing the containing entities card…

  - type: custom:hui-element
    card_type: glance
    columns: 4
    card_mod: &mod
      style: |
        ha-card {
          box-shadow: none;
          margin: -16px;
        }
    entities:
      - entity: binary_sensor.schimmel_alert
        name: Schimmel
      - entity: binary_sensor.co2_monitor_carbon_dioxide_detected_location_provided
        name: Co2 status
      - entity: binary_sensor.humidity_living_low
        name: Hum

  - type: custom:hui-element
    card_type: glance
    columns: 4
    card_mod: *mod
    entities:
      - entity: sensor.schimmel_sensor
        name: Mold
      - entity: sensor.co2_living
        name: Co2
      - entity: sensor.temperatuur_living
        name: Temp
      - entity: sensor.luchtvochtigheid_living
        name: Vocht

showing:

and Id like it to use more of the:

left and right side space (narrowing those margins). This seems a very default mod, so I can not imagine we didnt discuss this before… simply cant find it.
please help me out… thx!
(btw, not using stack-in-card, this is a regular entities with some modding only)

I’m building compact room cards using mushroom-cards. This card mod stretches the cover buttons so that they’re the same width as the light brightness control slider:

Before:
chrome_nJ8RPvzBTo

After:
chrome_z7RbZKQrrf

    card_mod:
      style:
        mushroom-card:
          .: |
            .actions {
              margin-right: 0px;
            }
          mushroom-cover-buttons-control $:
            mushroom-button-group:
              $: |
                .container {
                  justify-content: space-between !important;
                }
              .: |
                mushroom-button {
                  width: 30%;
                  margin-right: 0px;
                }
3 Likes

Any tips to put the entity icon inside the slider? I remember reading a post of yours showing how to stack entities on top of each other, I was thinking that was one of the options with the other being to disable full_row on the slider-entity-row and extend the slider all the way to the left.