šŸ”¹ Card-mod - Add css styles to any lovelace card

1st post ā†’ link at the bottom ā†’ styles for media-player

And next time please post your failed attempts w/o any excessive code which is not related to the issue.
Same is about using jinjia templates. First achieve a desired result w/o templates ā†’ then add templates.

Why should it?

Beside, that this is idea is wrong at all, because there is of course a iif, instead of guessing, Michele should always have a first look at the examples from Ildar and then have a look in the html dom, and try there changes in the browser. And you will directly see, that the background CSS attribute in ha-card is not related to the background to change.

1 Like

Good morning Ildar and thanks for the suggestions. I had completely missed all those examples you posted on the discussion, now I will certainly have less problems to configure my lovelace. Thanks again, and thanks for the tips on how to post, Iā€™ll treasure it.

Edit: Iā€™ve seen your posts, and used for my case this code

type: media-control
entity: media_player.kodi_iiyama
card_mod:
  style: |
    .background.no-image > * {
      background-color: cyan;
    }   

my question is simple: itā€™s possible to add an IF for choose background color according to the state of the media? E.g. Iā€™ve a PS4, itā€™s in IDLE status, but I see only cyan, and when itā€™s turned off I canā€™t choose the color. @Ildar_Gabdullin please can you help me?

No, Jinja: Templating - Home Assistant

1 Like

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.
Update 03.10.24: card-mod based solution seems to work 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