Custom Features for Home Assistant Cards - Buttons, Sliders, Selectors, and Spinboxes

I just noticed that the “style” options do no work when a card is seen wihtin the “Fully Kiosk Browser” app (it works with chrome on the same device). Note that cardmod styling works though. Any idea what could cause that ? Thanks !

Edit: the same behavior happens with the offical HA app, so I guess that the problem comes from the webview version on my device

Share your config. Do you have nested CSS styles? I know those don’t work with older Android webviews.

Here is an example :

features:
  - type: custom:service-call
    entries:
      - type: button
        entity_id: switch.cuisine_screen_automatic_control
        tap_action:
          action: toggle
          target:
            entity_id: switch.cuisine_screen_automatic_control
        label: Auto
        haptics: true
        styles: |-
          :host {
            {% if is_state("switch.cuisine_screen_automatic_control", "on") %}
            --color: green
            {% endif %}
            ;
          }
          .label {
            justify-content: center;
          }
      - type: button
        entity_id: switch.cuisine_screen_block
        tap_action:
          action: toggle
          target:
            entity_id: switch.cuisine_screen_block
        label: Block
        haptics: true
        styles: |-
          :host {
            {% if is_state("switch.cuisine_screen_block", "on") %}
            --color: rgb(255,0,0);
            {% endif %}
            ;
          }
      - type: button
        entity_id: cover.cuisine_screen
        icon: mdi:arrow-up
        tap_action:
          action: perform-action
          perform_action: cover.open_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        hold_action:
          action: perform-action
          perform_action: cover.stop_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        haptics: true
        styles: |-
          :host {
            {% if (is_state_attr("cover.cuisine_screen", "current_position", "100") or is_state("cover.cuisine_screen", "opening")) %}
            display: none;
            {% endif %}
          }
      - type: button
        entity_id: cover.cuisine_screen
        icon: mdi:stop
        tap_action:
          action: perform-action
          perform_action: cover.stop_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        hold_action:
          action: perform-action
          perform_action: cover.stop_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        haptics: true
        styles: |-
          :host {
            {% if (not is_state("cover.cuisine_screen", "opening") and not is_state("cover.cuisine_screen", "closing")) %}
            display: none;
            {% endif %}
          }
      - type: button
        entity_id: cover.cuisine_screen
        icon: mdi:arrow-down
        tap_action:
          action: perform-action
          perform_action: cover.close_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        hold_action:
          action: perform-action
          perform_action: cover.stop_cover
          target:
            entity_id:
              - cover.cuisine_screen
          data: {}
        haptics: true
        styles: |-
          :host {
            {% if (is_state_attr("cover.cuisine_screen", "current_position", "0") or is_state("cover.cuisine_screen", "closing")) %}
            display: none;
            {% endif %}
          }
type: tile
entity: cover.cuisine_screen
show_entity_picture: false
vertical: false
layout_options:
  grid_columns: 4
  grid_rows: 2
name: Screen Cuisine
icon: ''
hide_state: false
state_content: state
card_mod:
  style:
    .: |
      ha-card {
        --tile-color:
            {% set status = states(config.entity) %}
            {% if (is_state('binary_sensor.meteo_vent_limite_1','on')) %}
              {% set status = 'wind' %}
            {% endif %}
            {% set colors = {
              'open': 'grey',
              'closed': '#ffc105',
              'opening': '#663399',
              'closing': '#d3bd79',
              'unknown': 'white',
              'wind': 'red'
              } %}
            {{ colors.get(status, 'blue') }} !important; 
        }

How it should appear (works fine in Chrome, Edge, etc.) :

Capture d'écran 2024-09-03 083325

And how it appears on a device with an older webview, using Fully Kiosk Browser or the official HA app (Huawei MatePad Pro 12.4) :

So neither the “display: none;” nor the “–color: green;” styles work in this example.

Note that on my Pixel 8, with up to date webview, the card is showing correctly within the HA app.

Have you tried sideloading a newer version of Android System WebView? I was able to do something similar on Fire Tablets with Amazon System WebView a while ago and it fixed some performance and render issues for me.

who has got a good plex media card card for users you are sharing with?

You may want to check out Universal Remote Card, which is optimized for media use.

yeah i have that but im looking for plex card to show plex relate sensors, thanks though

Anyone with a quick tip on how to animate feature button icons? I struggle navigating into the shadow root and was not successful using .icon{} with any know commands.

You shouldn’t have to deal with any shadow roots for styles in these custom features? This works for me:

.icon {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  100% {
    transform: rotate(360deg)
  }
}

ahhhhh, I assumed the built in animation are inherited. That explains it! Thanks!

how did you do that fantastic tile title? I love it !

1 Like

Do you refer to the images? Those are just simple images I drew for myself with random photos, used by simple HA image cards.

Temperature and humidity values would be nice on them, but what HA offer for it is not perfect…

no I was talking about the background of the room name.

Great card! I like (mis-)using the slider without action as an alternative to the bar-card. Made this visualization for PV forecast.
image
Any chance to mend the actual value that is used to render the slider, maybe via css? Something like “:host {value: {{ calculation }} }”?
Ah, and while I am just seeing this, any way to center the individual lines of the multi-line label relative instead of having it left aligned?

Yeah, exactly those are which I mentioned… Those are simple custom raster images. I drew them 1 by 1 from random photos. I imagined an aspect ratio, drew the shape of the header, selected a font, and ‘dropped them together’, and at the end linked by an image card to HA, only to bring some life into my raw and dry dashboards…

Example:

(The photo is not mine, I’m just using it for my very own ‘internal’ goals…)

I’m not sure what you mean by mending the slider value. You can change the slider label value based on it’s actual value using templates like {{ value * 100 }}%. You can also adjust it’s range using the built in range options, and change these ranges using templates.

While both lines in the label are part of the same HTML inner text, you can change it’s overall alignment using css.

.label {
  text-align: center;
}

Thank you, the centering works :+1:

What I mean regarding the value is to not only adapt the label, but the value itself which is used to determine the slider position. I meanwhile worked around this with a helper entity I used for the “slider” which has my calculated value.

image
Now, though, another problem is revealed. In this screenshot the value for the left slider (the other ones are buttons in fact) is 0%. The thumb is set to “flat”, but it is still there and consumes space :confused: Would it be possible to completely get rid of the thumb, eg by setting its width to 0?

Another idea … it’s christmas soon :slight_smile: maybe you could gift us another feature type “bar” which looks similar to a slider but only displays the value as a bar gauge?

What I mean regarding the value is to not only adapt the label, but the value itself which is used to determine the slider position. I meanwhile worked around this with a helper entity I used for the “slider” which has my calculated value.

Does changing the range not work?

Now, though, another problem is revealed. In this screenshot the value for the left slider (the other ones are buttons in fact) is 0%. The thumb is set to “flat”, but it is still there and consumes space :confused: Would it be possible to completely get rid of the thumb, eg by setting its width to 0?

You can do two things, both using CSS styles: reduce the slider thumb width and hide the slider thumb when it’s at the range minimum value.

:host {
  --thumb-width: 4px;
}

{% if value == config.range[0] %}
::-webkit-slider-thumb {
  visibility: hidden;
}
::-moz-range-thumb {
  visibility: hidden;
}
.icon {
  visibility: hidden;
}
{% endif %}

maybe you could gift us another feature type “bar”

Nope.

hey again, love this hacs add on, re building alot of dashboards where im focusing on the devices with its entities.

Im trying to update my climate controller when when the climate state is cool , that the option selected is blue, and the icon turns white

entity_id: climate.izone_ac_controller_dining_room
option: Cool
tap_action:
  action: perform-action
  perform_action: climate.set_hvac_mode
  target:
    entity_id:
      - climate.izone_ac_controller_dining_room
  data:
    hvac_mode: cool
value_attribute: hvac_modes
icon: mdi:snowflake
styles: |-
  :host {
    --color: var(--blue-color);
    {% if is_state('climate.izone_ac_controller_dining_room', 'heat') %}
    --icon-color: var(--white-color);
    {% else %}
    --icon-color: var(--blue-color);
    {% endif %};
  }
  .icon {
    animation: spin 1s linear infinite;
  }
  @keyframes spin {
    100% {
      transform: rotate(360deg)
    }
  }

It looks like you just have to change 'heat' to 'cool'? Right now it’s changing the icon color to white when the state is heat.