Problem with JS on custom_fields inside button-card

First things first, I’m building a dashboard for my home and learning in the process. I want buttons wrapped in a stylized card, so I found out that my option was to build custom_fields inside a button-card. Here’s how it looks so far:

I’ve created an a/c button on a clean dashboard (sections mode) and it worked like a charm, this is the code:

type: custom:button-card
entity: climate.hvac
name: Mesa de jantar
show_icon: false
tap_action:
  action: call-service
  service: climate.set_hvac_mode
  service_data:
    entity_id: "[[[ return entity.entity_id ]]]"
    hvac_mode: |
      [[[ if (entity.state === "off") { return "cool"; } else { return "off"; }
      ]]]
state:
  - value: cool
    styles:
      card:
        - background: "#2196f3"
  - value: heat
    styles:
      card:
        - background: "#ff6f22"
  - value: "off"
    styles:
      card:
        - background: "#202020"
custom_fields:
  btn_minus:
    card:
      type: custom:button-card
      icon: mdi:minus
      show_name: false
      tap_action:
        action: call-service
        service: script.climate_temp_down_button
        service_data:
          climate_id: "[[[ return entity.entity_id ]]]"
          value: 1
      styles:
        card:
          - background: "#202020"
          - border: none
          - height: 34px
          - width: 34px
          - border-radius: 50% 0 0 50%
          - display: |
              [[[
                if (entity.state == "off") {
                return "none";
              } else {
                return "";
              } ]]]
  btn_plus:
    card:
      type: custom:button-card
      icon: mdi:plus
      show_name: false
      tap_action:
        action: call-service
        service: script.climate_temp_up_button
        service_data:
          climate_id: "[[[ return entity.entity_id ]]]"
          value: 1
      styles:
        card:
          - background: "#202020"
          - margin-right: 6px
          - border: none
          - height: 34px
          - width: 34px
          - border-radius: 0 50% 50% 0
          - display: |
              [[[
                if (entity.state == "off") {
                return "none";
              } else {
                return "";
              } ]]]
  temp:
    card:
      type: custom:button-card
      name: |
        [[[
          if (entity.state == "off") {
          return "";
        } else {
          return entity.attributes.temperature + "°";
        } ]]]
      styles:
        card:
          - background: "#202020"
          - border: none
          - height: 34px
          - width: 34px
          - border-radius: 0px
          - display: |
              [[[
                if (entity.state == "off") {
                return "none";
              } else {
                return "";
              } ]]]
  mode:
    card:
      type: custom:button-card
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: "[[[ return entity.entity_id ]]]"
          hvac_mode: |
            [[[
              if (entity.state == "off") {
              return "off";
            } else if (entity.state == "cool") {
              return "heat";
            } else {
              return "cool";
            } ]]]
      icon: |
        [[[
          if (entity.state == "off") {
          return "mdi:power";
        }  else if (entity.state == "cool") {
          return "mdi:fire";
        } else {
          return "mdi:snowflake";
        } ]]]
      styles:
        card:
          - background: "#202020"
          - border: none
          - height: 34px
          - width: 34px
          - border-radius: 50%
          - margin-right: 6px
        icon:
          - width: 25px
  fan:
    card:
      type: custom:button-card
      tap_action:
        action: call-service
        service: climate.set_fan_mode
        service_data:
          entity_id: "[[[ return entity.entity_id ]]]"
          fan_mode: |
            [[[
              const order = ["auto_low", "on_low", "auto_high", "on_high"];
              const current = entity.attributes.fan_mode;
              const next = order[(order.indexOf(current) + 1) % order.length];
              return next;
            ]]]
      icon: |
        [[[
          const mode = entity.attributes.fan_mode;
          if (mode === "auto_low") return "mdi:fan-auto";
          if (mode === "on_low") return "mdi:fan-speed-1";
          if (mode === "auto_high") return "mdi:fan-speed-2";
          if (mode === "on_high") return "mdi:fan-speed-3";
          return "mdi:fan";
        ]]]
      styles:
        card:
          - background: "#202020"
          - border: none
          - height: 34px
          - width: 34px
          - border-radius: 50%
          - margin-right: 6px
          - display: |
              [[[
                if (entity.state == "off") {
                return "none";
              } else {
                return "";
              } ]]]
        icon:
          - width: 25px
styles:
  card:
    - padding: 0px 0px 0px
    - border-radius: 14px
    - border: none
    - height: 40px
    - box-shadow: "0px 0px 10px 1px #080808"
  grid:
    - grid-template-columns: 1fr
    - grid-template-rows: auto
    - grid-template-areas: |
        "n mode fan btn_minus temp btn_plus"
  name:
    - justify-self: start
    - font-size: 16px
    - font-weight: 500
    - padding: 0px 20px

But the thing is, as soon as I put it inside a custom_field, everything broke. I’ve changed all references like “entity.entity_id” and “entity.state” and things like this to the actual name of the entity, but even simple code like this does not work:

cards:
  - type: custom:button-card
    view_layout:
      grid-area: ac
    name: Ar condicionado
    custom_fields:
      mesa:
        card:
          type: custom:button-card
          entity: climate.hvac
          name: Mesa de jantar
          label: "[[[ return states['climate.hvac'].state ]]]"
          show_label: true
          show_icon: false
          tap_action:
            action: call-service
            service: climate.set_hvac_mode
            service-data:
              entity_id: climate.hvac
              hvac_mode: >
                [[[ if (states['climate.hvac'].state == "off") { return "cool";
                } else { return "off"; } ]]]

The HVAC mode won’t change, but the label (that I used as a test tool) shows the right state. Is this an issue with custom_fields? At least ChatGPT told me it’s incompatible.

If that’s the case, what are my options for creating this wrapper without using custom_fields inside the button-card? Layout-card and vertical-stack can’t be stylized… Any help would be greatly appreciated.

You likely need to nest your JavaScript in the custom fields so it is evaluated in the custom field and not the main card. Checking out nesting templates in the button card docs.

1 Like

Quick thought… If the climate state starts in mode unavailable, heat, heat_cool or auto the change may be ignored.

Other issues too. Start with this…

custom_fields:
  mesa:
    card:
      type: custom:button-card
      entity: climate.hvac
      name: Mesa de jantar
      label: "[[[ return states['climate.hvac'].state ]]]"
      show_label: true
      show_icon: false
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        target:
          entity_id: climate.hvac
        data:
          hvac_mode: >
                [[[ if (states['climate.hvac'].state == "off") { return "cool";
                } else { return "off"; } ]]]

or understand…

service-data: should be service_data: in your original code

tap_action:
            action: call-service
            service: climate.set_hvac_mode
            service_data:
              entity_id: climate.hvac
              hvac_mode: >
                [[[ if (states['climate.hvac'].state == "off") { return "cool";
                } else { return "off"; } ]]]

This is it. When using js inside custom_fields you need to nest them into four [[[[

Thank you!