Lovelace: Button card

I’m not sure how to return anything in javascript (at least in button card, anyway) without it being in quotes based on all the examples provided in the repo.

Either way, I read that return false means ‘do not return anything’.

Definitely not. Do you have a source for that? Maybe you’re confusing the truthy and falsy values in YAML with this.

Regarding you original problem: Did you try changing'false' to false and 'true' to true?

Just this should do:

"[[[ return Number(window.innerWidth) > 1179); ]]]"

EDIT: show_name and show_state doesn’t support templating (see the docs).

2 Likes

Hi Pieter,

thanks for your reply - appreciated.

No, not confusing with YAML - I definitely read it whilst researching Javascript on stackoverflow or w3schools, but cannot find it now - maybe I misinterpreted the text. Thanks for correcting me.

thanks!

Well, that’s embarrassing, but I can see how I missed it. It doesn’t actually state that it doesn’t support templating, but all the options that do support tempting, explicitly state it. Thanks for pointing that out!

1 Like

Code for this card? Thanks

Hello esteemed tinkerers,

I’m a years-long user of button card but have not kept up with things in the past several years (kids!) and a recent HA update broke several cards that were working fine for years… they broke sometime between 2024.06 and 2024.10. I’m not up to speed on HA’s breaking changes.

I make heavy use of templating + decluttering cards and I’ve isolated the problem to the section below (remove it and the card functions). Have there been any breaking changes to HA over the past few months that would required a re-write here?

Lovelace Error:

ButtonCardJSTemplateError: TypeError: Cannot read properties of undefined (reading 'state') in 'if (states['sensor.chi'].state == "[[state2-2]]") return `<ha-icon icon="mdi:signal-dis...'

Relevant section of the broken card:

        custom1: |
          [[[
            if (states['[[sensor1-2]]'].state == "[[state1-2]]") 
              return `<ha-icon
                icon="mdi:[[icon1-2]]"
                style="width: 25px; height: 25px; color: steelblue;">
                </ha-icon><span>[[prefix1]]<span>${states['[[sensor1-1]]'].state}[[suffix1]]</span></span>`
            else 
              return `<ha-icon
                icon="mdi:[[icon1-1]]"
                style="width: 25px; height:25px; color: steelblue;">
                </ha-icon><span>[[prefix1]]<span>${states['[[sensor1-1]]'].state}[[suffix1]]</span></span>`
          ]]]  

I continue to look on my own but I’ve come up blank so far and don’t have as much time to dig (again, kids!) so I’ve come to the brain trust for ideas.

Thank you.

I’ve never seen the '[[sensor1-2]]' syntax. What is it supposed to do and is this in the documentation? It’s usually a literal sensor string (e.g. states['switch.myswitch'].state) or one uses the entity object directly (if its the card’s entity ID).

The error is saying that the sensor you’re getting from the full states object doesn’t exist.

It’s the common nomenclature for inserting variables from decluttering cards. The template is defined separately and then I can quickly duplicate cards with different variables by defining them in the card itself. Saves a lot of time longterm, so I’ve always used them all over my config.

I make heavy use of templating + decluttering cards

Apologies for not explaining what I meant by this in my post above.

Anyways, the JS templating has always read these variables just fine (and the rest of the button card config does read them just fine) – it seems to be only the button card templates that fail to read them properly, and I’m not sure if this is because of a breaking change in HA, or changes to how button card works, or something else.

1 Like

can you confirm the actual state to exist? the error message is quite specific, and as Pieter says refers to that particular entity not being available to the template

you could break it down to that particular section, by removing the template and inserting the entity directly, to see if that brings it back.

Then you would know if its the template, or the decluttering card breaking things.

1 Like

As do I, but haven’t observed any breaking changes.

Per @Mariusthvdb/@parautenbach, are you sure the states exist?

1 Like

The fault is probably in this part, for debug try not to use the decluttering template, but use a clean template for button-card.

Here it is confusing that for decluttering template is used for variable [[ ]], and button card everything that is in [[[ ]]] is javascript, for some variables it can happen that it doesn’t return the correct value and therefore error occurs :man_shrugging:

This is quite normal with a button card within a decluttering card.

@tismondo The double quotes seems odd though. I would have:

(states['[[sensor1-2]]'].state == '[[state1-2]]')
                                  ^            ^ single quote here
here

please do as we’ve asked you twice now, test without the decluttering card

you need to eliminate the root cause, and can do by verifying the direct config works. I thats ok, then build the decluttering bit by bit

also, make life easy on yourself, and use better variable names, because the ones you use now are prone to mixup and confusion

For a test I tried a similar decluttering template with button card, it works with double quotes. Probably in his case the sensor will be unavailable.
my templates looks like this
decluttering template

test_template:
  card:
    type: custom:button-card
    entity: '[[sensor1-2]]'
    show_name: false
    show_state: false
    show_label: true
    show_icon: false
    label: >
      [[[
        if (states['[[sensor1-2]]'].state == "[[state1-2]]") {
          return `<ha-icon icon="mdi:[[icon1-2]]"></ha-icon> Turn Off`;
        } else {
          return `<ha-icon icon="mdi:[[icon1-1]]"></ha-icon> Turn On`;
        }
      ]]]

button-card

cards:
  - type: custom:decluttering-card
    template: test_template
    variables:
      - sensor1-2: light.ceiling_lights
      - state1-2: 'on'
      - icon1-2: lightbulb-on
      - icon1-1: lightbulb-off

2024-10-21 17.18.24

1 Like

compound post I previously posted in card-mod.… since I have found no card-mod solution but do all in button-card now, Ill repost the set below:

this could be posted in a tile card or custom:button-card thread too, but since I am trying to find the right card-mod, I’ll start here…

I have this tile card mod

      type: tile
      icon: mdi:water
      name: ' '
      vertical: true
      tap_action:
        action: more-info
      card_mod:
        style: |
          .icon-container {
            border-radius: 24px;
            background: radial-gradient(var(--card-background-color) 60%,transparent calc(60% + 1px)),
            conic-gradient(var(--tile-color) {{states(config.entity)}}% 0%,
            var(--card-background-color) 0% 100%);
          }

which draws a perfect border according to the percentage of the entity:

I’d love to do the same with my light buttons, but cant find the right mod to do so:

I have some of these on a custom field:

  custom_fields:
    info: &info_light
      >
        [[[ if (entity.state === 'on' && entity.attributes.brightness) {
            var brightness = Math.round(entity.attributes.brightness/2.54);
            const radius = 20.5;
            const circumference = radius * 2 * Math.PI;
            return `
              <svg viewBox="0 0 50 50">
                <circle cx="25" cy="25" r="${radius}"
                  stroke="var(--button-card-light-color,var(--active-color))" stroke-width="2" fill="none"
                  style="transform: rotate(-90deg);transform-origin: 50% 50%;
                  stroke-dasharray: ${circumference};
                  stroke-dashoffset: ${circumference - brightness / 100 * circumference};" />
                <text x="50%" y="54%" fill="black" font-size="16" font-weight= "bold"
                  text-anchor="middle" alignment-baseline="middle">
                  ${brightness}<tspan font-size="10">%</tspan>
                </text>
              </svg>
            `;
          }
        ]]]

and that works fine:

Scherm­afbeelding 2024-10-23 om 17.44.58

. but in this case I want the border to be drawn on the img_cell of the button-card, or, checking the element in the dom, the .img-cell

so I copied that tile card mod over to

  card_mod:
    style: |
      .img-cell {
        border-radius: 24px;
        background: radial-gradient(var(--card-background-color) 60%,transparent calc(60% + 1px)),
        conic-gradient(var(--button-card-light-color) {{states(config.entity)}}% 0%,
        var(--card-background-color) 0% 100%);
      }

note I did change to the button-card-light-color, but nothing is happening…

this is the original button with a regular style section on the image_cell:

    img_cell:
      - justify-content: center
      - background: >
          [[[ var rgb = (entity.state === 'on')
                ? entity.attributes.rgb_color : '211,211,211';
              return 'rgba(' + rgb + ',0.2)'; ]]]
      - border-radius: 24px
      - place-self: start
      - width: 42px
      - height: 42px

Scherm­afbeelding 2024-10-23 om 17.39.29

but when I take that out, and change to the card-mod there is nothing:

tbh, I wouldn’t yet know how to write the background in styles syntax native to the custom:button-card, thats why I tried it with card-mod

please have a look what could be done to fix this?

Follow up

well there is progress:

      - background: >
          [[[ var rgb = (entity.state === 'on')
                ? entity.attributes.rgb_color : '211,211,211';
              var rgba = 'rgba(' + rgb + ',0.2)';
              if (entity.state === 'on')
              return `radial-gradient(${rgba} 80%,transparent calc(60% + 1px)),
                      conic-gradient(var(--button-card-light-color) ${Math.round(entity.attributes.brightness/2.55)}% 0%,
                      var(--card-background-color) 0% 100%)`;
             return `${rgba}`; ]]]

and

  triggers_update:
    - entity

does a lot of good, thanks to @khaisilk1910 for helping me in Discord!

the final thing I need now is get rid of the actual conic, and have the background inside the img_cell only show that conic in the outer border…

just like in the print cartridge buttons…
I cant see it though

alternative since there is no apparent way to do as I hoped:

    img_cell:
      - justify-content: center
      - background: >
          [[[ var rgb = entity.state === 'on'
                ? entity.attributes.rgb_color : '211,211,211';
              var rgba = 'rgba(' + rgb + ',0.2)';

              return entity.state === 'on'
              ? `radial-gradient(var(--card-background-color) 60%,transparent calc(60% + 1px)),
                 conic-gradient(var(--button-card-light-color) ${Math.round(entity.attributes.brightness/2.55)}% 0%,
                 ${rgba} 0% 100%)`
              : `${rgba}`; ]]]

___ And finally at least 1 solution___

it has to do with the left over section of the overlay (but no, it didnt make any difference in solar I could find out)

I’ve found another solution now though:

I am using the same info custom field, and I overlay it exactly over the icon img_cell of the button-card. It feels a bit hacky, and ofc its not 100% linked to the img_cell itself (not all as a matter of fact, it’s just a custom field after all) but is is the best I could come up with for now.

CSS for the border percentage....
  custom_fields:
    info: >
      [[[ if (entity.state === 'on' && entity.attributes.brightness) {
          var brightness = Math.round(entity.attributes.brightness/2.54);
          var rgb = (entity.state === 'on')
                  ? entity.attributes.rgb_color : '211,211,211';
          var rgba = 'rgba(' + rgb + ',0.2)';
          const radius = 20.5;
          const circumference = radius * 2 * Math.PI;
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="${radius}"
                stroke="var(--button-card-light-color,var(--active-color))" stroke-width="2" fill="${rgba}"
                style="transform: rotate(-90deg);transform-origin: 50% 50%;
                stroke-dasharray: ${circumference};
                stroke-dashoffset: ${circumference - brightness / 100 * circumference};" />
            </svg>
          `;
        }
      ]]]

  styles:
    custom_fields:
      info:
        - position: absolute
        - left: 2%
        - top: 4%
        - width: 48px

Scherm­afbeelding 2024-10-25 om 11.50.34

OMT:

I can omit the

triggers_update:
  - entity

after all. It was unexpected I needed it before, but now the templates are working, the card successfully triggers automatically

2 Likes

Love it! Great CSS work…

1 Like

Brilliant - thanks for sharing!

1 Like

small update, because there were some anomalies in the on state without rgb_color attribute (showing the 211,211,211 color…) and I added some unavailable/unknown colors.

  custom_fields:
    info: >
      [[[ if (entity.state === 'on' && entity.attributes.brightness) {
            var brightness = Math.round(entity.attributes.brightness/2.54);
            var rgb = (entity.attributes.rgb_color)
                       ? entity.attributes.rgb_color : '254,181,13' ;
          }
          if (entity.state === 'off') {
            var rgb = '211,211,211';
          }
          if (entity.state in ['unknown','unavailable']) {
            var rgb = '189,189,189';
          }
          var rgba = 'rgba(' + rgb + ',0.2)';
          const radius = 20.5;
          const circumference = radius * 2 * Math.PI;
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="${radius}"
                stroke="var(--button-card-light-color,var(--active-color))"
                stroke-width="3"
                fill="${rgba}"
                style="transform: rotate(-90deg);transform-origin: 50% 50%;
                stroke-dasharray: ${circumference};
                stroke-dashoffset: ${circumference - brightness / 100 * circumference};" />
            </svg>
          `;
      ]]]

  styles:
    custom_fields:
      info:
        - position: absolute
        - left: 1%
        - top: 4%
        - width: 50px

also notice the styling/position change… it had to be 50 because of the viewbox using 50px too…
next to that, you’ve got to be aware the button-card’s background still exists. So, when using a darker theme the color of the circle gets frustrated by that darker background color.

Ive tried background transparent, but obviously that doesnt help, as it makes the card background even more prominent :wink:

so for now I’ve settled to do something like:

    img_cell:
      - justify-content: center
      - background: >
          [[[ if (entity.state === 'on') return 'ivory';]]]

but, that isnt optimal either (as it leaves the unused brightness area in that color. o well, its not simple at all

light theme is perfect though:

Other options to play with:
set the color of the img_cell background to the exact same color as the fill of the custom-field, not really any help

set

fill-opacity:1
fill-rule="nonzero"

to the svg view box, and play with that. doesn’t really help either.

3 Likes

Hey all, I’m trying to get colors represented on my button card when entity state changes and it seems to be ignoring the entire section where that is defined.

type: custom:button-card
name: Mark
show_name: false
show_state: false
show_icon: true
show_entity_picture: true
entity: person.mark_ramos
tap_action:
  action: perform-action
  perform_action: icloud3.find_iphone_alert
  data:
    device_name: abcdef0123456
entity_id: device_tracker.mark_iphone
styles:
  card:
    - background-color: var(--contrast2)
    - padding: 10px 10px 10px 0px
  grid:
    - grid-template-areas: "\"icon name btn\" \"icon state btn\""
    - grid-template-columns: 60px 1fr min-content
    - grid-template-rows: min-content
  img_cell:
    - justify-content: start
    - position: absolute
    - width: 40px
    - height: 40px
    - left: 0
    - bottom: 0
    - margin: 0 0 8px 10px
    - border-radius: 50%
    - border: |
        [[[
          if (entity.state == 'home') {
            return '1px solid var(--green)';
          } else {
            return 'none';
          }
        ]]]
  entity_picture:
    - justify-content: start
    - position: absolute
    - width: 40px
    - height: 40px
    - left: 0
    - bottom: 0
    - margin: 0 0 0 0
    - border-radius: 500px
  icon:
    - width: 50px
    - color: var(--contrast1)
  custom_fields:
    name:
      - align-self: start
      - justify-self: start
      - background: none
      - padding: 0
    state:
      - align-self: start
      - justify-self: start
      - background: none
      - padding: 0
      - margin-top: "-5px"
    btn:
      - align-self: end
      - justify-self: end
    icon:
      - align-self: start
      - justify-self: start
    badge:
      - position: absolute
      - left: 38px
      - top: 7px
custom_fields:
  name:
    card:
      type: custom:button-card
      name: Mark
      styles:
        card:
          - color: var(--contrast20)
          - font-size: 14px
          - font-weight: 600
          - background: none
  state:
    card:
      type: custom:button-card
      entity: "[[[ return entity.entity_id ]]]"
      show_icon: false
      name: |
        [[[ 
          return states['person.mark_ramos'].state;
        ]]]
      state:
        - value: home
          name: Home
        - value: not_home
          name: Away
      styles:
        card:
          - color: var(--contrast20)
          - font-size: 12px
          - background: none
          - opacity: "0.7"
  badge:
    card:
      type: custom:button-card
      entity: "[[[ return entity.entity_id ]]]"
      show_icon: true
      show_name: false
      icon: mdi:home
      state:
        - value: home
          icon: mdi:home
          styles:
            card:
              - background: var(--green)
        - value: not_home
          icon: mdi:home-export-outline
          styles:
            card:
              - background: var(--red)
      styles:
        card:
          - border-radius: 50%
          - width: 16px
          - height: 16px
          - background: none
        icon:
          - color: black
          - width: 12px
  btn:
    card:
      type: custom:mushroom-chips-card
      chips:
        - type: entity
          tap_action:
            action: more-info
          entity: sensor.mark_iphone_battery_3
          content_info: none
          card_mod:
            style: |
              ha-card {
                --chip-background: {{ 'var(--contrast4)' if states('sensor.mark_iphone_battery_3') | float > 10  else 'var(--red)' }};
                --color: {{ 'var(--contrast20)' if states('sensor.mark_iphone_battery_3') | float > 10  else 'var(--black)' }};
                padding: 0px!important;
                border-radius: 100px!impportant;
                --primary-text-color: var(--contrast20);

Didn’t you try to set a specific color for debug instead of css variables? Isn’t there a problem with them?

Thanks, that got me a bit further. I do think it’s related to an override somewhere in my dashboard, not within the card. I’m searching…