šŸ“ 100% Templatable Lovelace Configurations

I think this was a bit confusing release note)))))
It was already possible to refer variables in this way)

Hello, I’d like to combine template lovelace with fluid-level-baground-card but can’t get it to work.
This is mycode so far:

type: horizontal-stack
cards:
  - type: custom:config-template-card
    entities:
      - sensor.ibc_mitte
    card:
      type: custom:fluid-level-background-card
      graph: none
      type: sensor
      entity: sensor.ibc_mitte
      detail: 1
      full_value: "1000"
      severity: []
      fill_entity: sensor.ibc_mitte
      name: "{{ states('sensor.ibc_mitte') }}"  # Dynamischer Name basierend auf dem Wert von sensor.ibc_mitte
  - type: custom:config-template-card
    entities:
      - sensor.ibc_oben
    card:
      type: custom:fluid-level-background-card
      graph: none
      type: sensor
      entity: sensor.ibc_oben
      detail: 1
      full_value: "1000"
      severity: []
      fill_entity: sensor.ibc_oben
      name: "{{ states('sensor.ibc_oben') }}"  # Dynamischer Name basierend auf dem Wert von sensor.ibc_oben

Making a sandwich only to change a ā€œnameā€?
In general, the code which you use in templates is wrong. You are trying to use jinja, the card supports JS. Check examples in docs.

Thank you, I’m new to this stuff.

Ok, I see… I changed my code but it doesn’t work…

type: horizontal-stack
cards:
  - type: custom:config-template-card
    variables:
      IBC: states['sensor.ibc_mitte'].state
    entities:
      - sensor.ibc_mitte
    card:
      type: custom:fluid-level-background-card
      graph: none
      type: sensor
      entity: sensor.ibc_mitte
      detail: 1
      full_value: "1000"
      severity: []
      fill_entity: sensor.ibc_mitte
      name: "${IBC}"  # Dynamischer Name basierend auf dem Wert von sensor.ibc_mitte
  - type: custom:config-template-card
    variables:
      IBC2: states['sensor.ibc_oben'].state
    entities:
      - sensor.ibc_oben
    card:
      type: custom:fluid-level-background-card
      graph: none
      type: sensor
      entity: sensor.ibc_oben
      detail: 1
      full_value: "1000"
      severity: []
      fill_entity: sensor.ibc_oben
      name: "${IBC2}"  # Dynamischer Name basierend auf dem Wert von sensor.ibc_oben

I would suggest you to test with a stock Entity card first.

`Hello together,

I would like to use your map to automatically read out HUE scenes in the attributes and then display them as buttons in a horizontal slider or as a grid.
The aim is to automatically display newly created scenes with the hue app in the HA dashboard

Example entity:
light.jan_az_2

Attribute:
  min_color_temp_kelvin: 2202
  max_color_temp_kelvin: 6535
  min_mireds: 153
  max_mireds: 454
  supported_color_modes: color_temp, xy
  color_mode: color_temp
  brightness: 255
  color_temp_kelvin: 4000
  color_temp: 250
  hs_color: 26.812, 34.87
  rgb_color: 255, 206, 166
  xy_color: 0.42, 0.365
  is_hue_group: true
  hue_scenes: Color Burst, Nordlichter, Hell, Verträumter Sonnenuntergang, Nachtlicht, Unter dem Baum, Ruhephase, Krokus, Kühl hell, Natürliches Licht, Miami, Rio, Entspannen
  hue_type: room
  lights: Hue Play 1, Hue Play 2, Jan AZ
  entity_id: light.hue_play_2, light.jan_az, light.hue_play_1
  dynamics: false
  icon: mdi:lightbulb-group
  friendly_name: Jan AZ
  supported_features: 40

the following code correctly lists the scenes:

type: markdown
entity_id: light.jan_az_2
content: "{{ states.light.jan_az_2.attributes.hue_scenes }}"

Result:
Color Burst,Nordlichter,Hell,Verträumter Sonnenuntergang,Miami,Nachtlicht,Unter dem Baum,Ruhephase,Krokus,Natürliches Licht,Kühl hell,Rio,Entspannen

I currently use the following code in the dashboard (manuell)

  type: vertical-stack
  cards:
    - square: false
      type: grid
      columns: 3
      title: Szenen
      cards:
        - type: tile
          entity: scene.jan_az_naturliches_licht
          hide_state: true
          tap_action:
            action: toggle
          name: Natürliches Licht
          vertical: true
        - type: tile
          entity: scene.jan_az_hell
          hide_state: true
          tap_action:
            action: toggle
          name: Hell

So far I have only received code errors or blank cards. Can you help me here? Thanks a lot for helping

type: 'custom:config-template-card'
variables:
 
  SCENES: states['light.jan_az_2'].attributes.hue_scenes
    ? states['light.jan_az_2'].attributes.hue_scenes.split(',')
    : []
entities:

  - light.jan_az_2

card:
  type: vertical-stack

  cards: >
    ${SCENES.map(scene => `
    - type: tile
      # Wir bauen den Scene-Entity-Namen, z.B. "scene.jan_az_color_burst"
      entity: scene.jan_az_${scene.trim().toLowerCase().replace(/ /g, "_")}
      name: "${scene.trim()}"
      tap_action:
        action: toggle
      vertical: true
    `).join('')}

Nevermind. I just modified the integration to create the sensors even when not used and it will solve my problem.

If this is a repeated question, please let me know where to find the answer. I could not find it. If a new thing, any clue on what should be done to solve the situation I will report below?

I have a complex card panel using the config-template-card and this helps me a lot to dynamically load my entities based on the value set for a SELECT entity. Amazing.

My problem occurs when some of these entities don’t exist for the selected value.
To make it clear:
The entities are created by a MQTT integration. Sometimes some of the expected entities for this panel may not be created and the entity will no longer exists.

When it happens, if two or more entities are missing, the config-template-card just does not load anything. Just a blank card.

This is a useful scenario ā€œcreate a list of cards dynamicallyā€.
Use this example as a starting point:

  - type: custom:config-template-card
    variables:
      LIGHTS: |-
        Object.keys(states).filter(
          k => k.startsWith('light')
        )
    entities: ${LIGHTS}
    card:
      type: grid
      title: xxx
      square: false
      columns: 3
      cards: >-
        ${
          let cards = [];
          LIGHTS.map(entity =>
            cards = cards.concat(
              {
                'type':'tile',
                'entity':entity
              }
            )
          );
          cards;
        }

P.S. Tested with beta 3.17.

Thanks a lot. It was really helpfull. I got it now as I wantet:
I work with a hue bridge. Die Scenes are read out and sorted to rooms. In the first row are all standard scenes displayed. In the second, the scenes (except the standard scenes) have a brightness of 255 - 194, in the third 193 to 67 and in the last 66 to 0.

Here is my config, maybe it will help someone else:

I installed:

I created entities
- input_number.dashboard_scenes_brightness_1 (0 - 255; step:1, value 193)
- input_number.dashboard_scenes_brightness_2 (0 - 255; step:1, value 66)
- input_number.dashboard_scenes_slidesperview (1 - 6; step: 1, value 3)
- input_number.dashboard_scenes_freemodemomentumratio (0 - 1; step: 0.1, value 0.5)
- input_number.dashboard_scenes_freemodemomentumvelocityratio (0 - 1; step: 0.1, value 0.5)

square: false
type: grid
columns: 1
cards:
  - type: custom:config-template-card
    variables:
      SCENES: |-

        //Nur folgende Szenen anzeigen und sortieren
         let customOrder = {
           'scene.wohnzimmer_naturliches_licht': 1,
           'scene.wohnzimmer_hell': 2,
           'scene.wohnzimmer_kuhl_hell': 3,
           'scene.wohnzimmer_energie_tanken' : 4,
           'scene.wohnzimmer_konzentrieren' : 5,
           'scene.wohnzimmer_lesen' : 6,      
           'scene.wohnzimmer_entspannen': 7,
           'scene.wohnzimmer_ruhephase': 8,
           'scene.wohnzimmer_nachtlicht': 9

         };

         Object.keys(states)
         .filter(
           k => k.startsWith('scene.wohnzimmer')
         )
         .filter(k => Object.keys(customOrder).includes(k))
         .sort((a, b) => customOrder[a] - customOrder[b])
      SLIDESPERVIEW: parseFloat(states['input_number.dashboard_scenes_slidesperview'].state);
      MOMENTUMRATIO: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumratio'].state);
      MOMENTUMVEL: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumvelocityratio'].state);
    entities:
      - ${SCENES}
      - input_number.dashboard_scenes_brightness_1
      - input_number.dashboard_scenes_brightness_2
      - input_number.dashboard_scenes_slidesperview
      - input_number.dashboard_scenes_freemodemomentumratio
      - input_number.dashboard_scenes_freemodemomentumvelocityratio
    card:
      type: custom:swipe-card
      parameters:
        slidesPerView: ${SLIDESPERVIEW}
        spaceBetween: 8
        freeMode: true
        freeModeMomentum: true
        freeModeMomentumRatio: ${MOMENTUMRATIO}
        freeModeMomentumVelocityRatio: ${MOMENTUMVEL}
      cards: |-
        ${
          let cards = [];
          SCENES.map(entity =>
            cards = cards.concat(
              {
                'type':'tile',
                'entity':entity,
                //Anzeige formatieren -> Ohne _ und Anfangsbuchstaben groß schreiben
                'name': entity.replace("scene.wohnzimmer_", "")
                  .replaceAll("_", " ")
                  .split(" ")
                  .map(w => w
                    .charAt(0)
                    .toUpperCase() + 
                    w.slice(1))
                      .join(" "),
                'vertical': true,
                'hide_state': true,
                'tap_action': {'action': 'toggle'}
              }
            )
          );
          cards;
        }
  - type: custom:config-template-card
    variables:
      SCENES: >-
        let allScenes = Object.keys(states)

        .filter(
          k => k.startsWith('scene.wohnzimmer')
        )
         //folgende Scenen herausfiltern und restliche Aplhabetisch sortieren
        .filter(k => ![
          'scene.wohnzimmer_naturliches_licht',
          'scene.wohnzimmer_hell',
          'scene.wohnzimmer_kuhl_hell',
          'scene.wohnzimmer_energie_tanken',
          'scene.wohnzimmer_konzentrieren',
          'scene.wohnzimmer_lesen',
          'scene.wohnzimmer_entspannen',
          'scene.wohnzimmer_ruhephase',
          'scene.wohnzimmer_nachtlicht'
        ].includes(k)).sort()

        ;



        // Szenen die trotz Helligkeitsfilter dargestellt werden sollen

        let mustInclude = [
          'scene.wohnzimmer_kuhl_dummy',
          'scene.wohnzimmer_galaxie_dummy2',
          // usw.
        ];


        allScenes = allScenes.filter(sceneID => {
          // 1) Falls die Szene in mustInclude gelistet ist
          if (mustInclude.includes(sceneID)) {
            return true;
          }

         //Nur Szenen anzeigen die Zwischen den Helligkeitswerten liegen
        let B1 =
        parseInt(states['input_number.dashboard_scenes_brightness_1'].state);

        let B2 =
        parseInt(states['input_number.dashboard_scenes_brightness_2'].state);
          
        let brightness = states[sceneID].attributes.brightness;      

        return brightness && brightness > B1 && brightness <= 255;

        });
      SLIDESPERVIEW: parseFloat(states['input_number.dashboard_scenes_slidesperview'].state);
      MOMENTUMRATIO: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumratio'].state);
      MOMENTUMVEL: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumvelocityratio'].state);
    entities:
      - ${SCENES}
      - input_number.dashboard_scenes_brightness_1
      - input_number.dashboard_scenes_brightness_2
      - input_number.dashboard_scenes_slidesperview
      - input_number.dashboard_scenes_freemodemomentumratio
      - input_number.dashboard_scenes_freemodemomentumvelocityratio
    card:
      type: custom:swipe-card
      parameters:
        slidesPerView: ${SLIDESPERVIEW}
        spaceBetween: 8
        freeMode: true
        freeModeMomentum: true
        freeModeMomentumRatio: ${MOMENTUMRATIO}
        freeModeMomentumVelocityRatio: ${MOMENTUMVEL}
      cards: |-
        ${
          let cards = [];
          SCENES.map(entity =>
            cards = cards.concat(
              {
                'type':'tile',
                'entity':entity,
                //Anzeige formatieren -> Ohne _ und Anfangsbuchstaben groß schreiben
                'name': entity.replace("scene.wohnzimmer_", "")
                  .replaceAll("_", " ")
                  .split(" ")
                  .map(w => w
                    .charAt(0)
                    .toUpperCase() + 
                    w.slice(1))
                      .join(" "),            'vertical': true,
                'color': 'orange',
                'hide_state': true,
                'tap_action': {'action': 'toggle'}
              }
            )
          );
          cards;
        }
  - type: custom:config-template-card
    variables:
      SCENES: >-
        let allScenes = Object.keys(states)

        .filter(
          k => k.startsWith('scene.wohnzimmer')
        )
         //folgende Scenen herausfiltern und restliche Aplhabetisch sortieren
        .filter(k => ![
          'scene.wohnzimmer_naturliches_licht',
          'scene.wohnzimmer_hell',
          'scene.wohnzimmer_kuhl_hell',
          'scene.wohnzimmer_energie_tanken',
          'scene.wohnzimmer_konzentrieren',
          'scene.wohnzimmer_lesen',
          'scene.wohnzimmer_entspannen',
          'scene.wohnzimmer_ruhephase',
          'scene.wohnzimmer_nachtlicht'
        ].includes(k)).sort()

        ;



        // Szenen die trotz Helligkeitsfilter dargestellt werden sollen

        let mustInclude = [
          'scene.wohnzimmer_kuhl_dummy',
          'scene.wohnzimmer_galaxie_dummy2',
          // usw.
        ];


        allScenes = allScenes.filter(sceneID => {
          // 1) Falls die Szene in mustInclude gelistet ist
          if (mustInclude.includes(sceneID)) {
            return true;
          }

         //Nur Szenen anzeigen die Zwischen den Helligkeitswerten liegen
        let B1 =
        parseInt(states['input_number.dashboard_scenes_brightness_1'].state);

        let B2 =
        parseInt(states['input_number.dashboard_scenes_brightness_2'].state);
          
        let brightness = states[sceneID].attributes.brightness;      

        return brightness && brightness > B2 && brightness <= B1;

        });
      SLIDESPERVIEW: parseFloat(states['input_number.dashboard_scenes_slidesperview'].state);
      MOMENTUMRATIO: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumratio'].state);
      MOMENTUMVEL: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumvelocityratio'].state);
    entities:
      - ${SCENES}
      - input_number.dashboard_scenes_brightness_1
      - input_number.dashboard_scenes_brightness_2
      - input_number.dashboard_scenes_slidesperview
      - input_number.dashboard_scenes_freemodemomentumratio
      - input_number.dashboard_scenes_freemodemomentumvelocityratio
    card:
      type: custom:swipe-card
      parameters:
        slidesPerView: ${SLIDESPERVIEW}
        spaceBetween: 8
        freeMode: true
        freeModeMomentum: true
        freeModeMomentumRatio: ${MOMENTUMRATIO}
        freeModeMomentumVelocityRatio: ${MOMENTUMVEL}
      cards: |-
        ${
          let cards = [];
          SCENES.map(entity =>
            cards = cards.concat(
              {
                'type':'tile',
                'entity':entity,
                //Anzeige formatieren -> Ohne _ und Anfangsbuchstaben groß schreiben
                'name': entity.replace("scene.wohnzimmer_", "")
                  .replaceAll("_", " ")
                  .split(" ")
                  .map(w => w
                    .charAt(0)
                    .toUpperCase() + 
                    w.slice(1))
                      .join(" "),            'vertical': true,
                'color': 'teal',
                'hide_state': true,
                'tap_action': {'action': 'toggle'}
              }
            )
          );
          cards;
        }
  - type: custom:config-template-card
    variables:
      SCENES: >-
        let allScenes = Object.keys(states)
         //folgende Scenen herausfiltern und restliche Aplhabetisch sortieren
        .filter(
          k => k.startsWith('scene.wohnzimmer')
        )

        .filter(k => ![
          'scene.wohnzimmer_naturliches_licht',
          'scene.wohnzimmer_hell',
          'scene.wohnzimmer_kuhl_hell',
          'scene.wohnzimmer_energie_tanken',
          'scene.wohnzimmer_konzentrieren',
          'scene.wohnzimmer_lesen',
          'scene.wohnzimmer_entspannen',
          'scene.wohnzimmer_ruhephase',
          'scene.wohnzimmer_nachtlicht'
        ].includes(k)).sort()

        ;



        // Szenen die trotz Helligkeitsfilter dargestellt werden sollen

        let mustInclude = [
          'scene.wohnzimmer_kuhl_dummy',
          'scene.wohnzimmer_galaxie_dummy2',
          // usw.
        ];


        allScenes = allScenes.filter(sceneID => {
          // 1) Falls die Szene in mustInclude gelistet ist
          if (mustInclude.includes(sceneID)) {
            return true;
          }

         //Nur Szenen anzeigen die Zwischen den Helligkeitswerten liegen

        let B1 =
        parseInt(states['input_number.dashboard_scenes_brightness_1'].state);

        let B2 =
        parseInt(states['input_number.dashboard_scenes_brightness_2'].state);
          
        let brightness = states[sceneID].attributes.brightness;      

        return brightness && brightness >= 0 && brightness <= B2;

        });
      SLIDESPERVIEW: parseFloat(states['input_number.dashboard_scenes_slidesperview'].state);
      MOMENTUMRATIO: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumratio'].state);
      MOMENTUMVEL: >-
        parseFloat(states['input_number.dashboard_scenes_freemodemomentumvelocityratio'].state);
    entities:
      - ${SCENES}
      - input_number.dashboard_scenes_brightness_1
      - input_number.dashboard_scenes_brightness_2
      - input_number.dashboard_scenes_slidesperview
      - input_number.dashboard_scenes_freemodemomentumratio
      - input_number.dashboard_scenes_freemodemomentumvelocityratio
    card:
      type: custom:swipe-card
      parameters:
        slidesPerView: ${SLIDESPERVIEW}
        spaceBetween: 8
        freeMode: true
        freeModeMomentum: true
        freeModeMomentumRatio: ${MOMENTUMRATIO}
        freeModeMomentumVelocityRatio: ${MOMENTUMVEL}
      cards: |-
        ${
          let cards = [];
          SCENES.map(entity =>
            cards = cards.concat(
              {
                'type':'tile',
                'entity':entity,
                //Anzeige formatieren -> Ohne _ und Anfangsbuchstaben groß schreiben
                'name': entity.replace("scene.wohnzimmer_", "")
                  .replaceAll("_", " ")
                  .split(" ")
                  .map(w => w
                    .charAt(0)
                    .toUpperCase() + 
                    w.slice(1))
                      .join(" "),            'vertical': true,
                'color': 'purple',
                'hide_state': true,
                'tap_action': {'action': 'toggle'}
              }
            )
          );
          cards;
        }
title: Szenen
visibility:
  - condition: state
    entity: input_boolean.dashboard_scene_configtemplate
    state: "on"

Hello, with this source code all the lights are displayed in the Lovelace GUI, but when I turn on a light, the GUI does not update. The light only appears as ā€œonā€ after I completely reload the page.

Use the latest version.

Beta Version?

Dev version.

This is a great card. I need help with one thing. I’m trying to select a device from an entity using a drop down (sorry if I am not using correct terms). For example I have three lights and a dropdown with [ā€˜light 1’, ā€˜light 2’, ā€˜light 3’]. I’d like to loop through my lights and find the one selected in the dropdown. I can do it in a jinja template but I don’t know how to translate the object references to js so I can use the config-template-card.

{% set ns = namespace(id_var = 'test') %}
{% for state in states.light %}
  {% if state.name == states.input_select.light_list.state %}
    {% set ns.id_var = state.entity_id %}
  {% endif %}
{% endfor %}  

works in a standard template. (I want to use this across multiple domains so the light reference is an example but I may want to use switch, climate, etc.
I’m using HAos running on debian 12 in a virtual box.
HA version 2025.5.2
template card 1.3.7-beta.1
Thanks!

I am away from PC, cannot test myself, but - why do you need a loop? Why not using smth like

set ID = (states.light | selectattr(ā€˜name’,’match’,states(ā€˜input_select.xxx’)) | list)[0]

(may be quotes should be replaced by proper ones, typing from a mobile).

As for changing this to JS:
better to refactor your loop version to JS. Will try to post it later (also untested). No promises though.

Meanwhile - google smth like ā€œJS playgroundā€, you will find sites to test JS code online.

1 Like

I’m old and cut my teeth on assembly language and 8 bit machines. :grin: For loops are my old stand-by. I’ll give your suggestion and the web sites a try. If you post again with the js loop I’ll learn from that too. Thanks a lot for the help!

1 Like

I suspect it is a mistake on my part but wasn’t able to get this to work. I entered the below in the variables: section of my custom:config-template-card (I’m trying it with my cameras). Any direction you can provide will be most appreciated. Thanks

edit: I just realized that the variable ID is created to contain the result of my search, continuing to experiment.

Snippet from my config template card

**test_forum: |**
**    set ID = (states.camera |selectattr(ā€˜name’,’match’,states(ā€˜input_select.camera_list’)) | list)[0]**

which results in the card going blank. I tried it in my HA studio code server add on and got the following ( I also tried it in my stand alone Visual Studio Code program, using an object I created for testing and a string in place of input_select…, this didn’t seem to like the word ā€œIDā€).

set ID = (states.light | selectattr(ā€˜name’,’match’,states(ā€˜input_select.camera_list’)) | list)[0] with ā€˜name’ in strike through text and 9 problems including the two below which seems to not like the keyword ā€œsetā€
[{
ā€œresourceā€: ā€œ/config/test-js-loops.jsā€,
ā€œownerā€: ā€œtypescriptā€,
ā€œcodeā€: ā€œ1434ā€,
ā€œseverityā€: 8,
ā€œmessageā€: ā€œUnexpected keyword or identifier.ā€,
ā€œsourceā€: ā€œtsā€,
ā€œstartLineNumberā€: 1,
ā€œstartColumnā€: 1,
ā€œendLineNumberā€: 1,
ā€œendColumnā€: 4
}]
[{
ā€œresourceā€: ā€œ/config/test-js-loops.jsā€,
ā€œownerā€: ā€œtypescriptā€,
ā€œcodeā€: ā€œ1135ā€,
ā€œseverityā€: 8,
ā€œmessageā€: ā€œArgument expression expected.ā€,
ā€œsourceā€: ā€œtsā€,
ā€œstartLineNumberā€: 1,
ā€œstartColumnā€: 43,
ā€œendLineNumberā€: 1,
ā€œendColumnā€: 44
}]

I’m having trouble navigating the entity references in the js as used in this config-template-card. This is a somewhat generic question as I would use the solution in a variety of things I want to try. Using a suggestion from the always helpful Ildar_Gabdullin I got this far:

type: custom:config-template-card
variables:
  lghts: |-
    Object.keys(states)
    .filter(
      kx => kx.startsWith('light')
      )

which seems to give me an array of all my light objects (?). I would like to be able to access some attributes, like name / friendly_name (as documented in each entity) but am having no luck.
Tried adding both a second filter and a map to the above using various iterations of map or filter(k => k.name) with no luck. I can use ${lght[2]} to set the entity of a card successfully, but I’d able to use a name comparison in the function to choose the desired light as opposed to using an array index. Thanks for any help!

I’m trying to set an icon based on my theme. Even if I try to define a variable with the path to it directly, the card isn’t displaying (#shadow-root is empty). I can’t figure out what I’m doing wrong…

          - type: custom:config-template-card
            entities: []
            variables: 
              - this_icon: |
                  const c = "/local/images/prime-video2-white-cropped.svg";
                  c;
            card:
              type: custom:button-card
              entity: []
              show_entity_picture: true
              # entity_picture: "/local/images/prime-video2-white-cropped.svg"
              entity_picture: ${this_icon} 

EDIT: Realized it was the - before this_icon, but doesn’t seem like it’s able to pull in theme variables:

          - type: custom:config-template-card
            entities: []
            variables: 
              ICON: |
                  const c = "/local/images/prime-video2-white-cropped.svg";
                  c;
              a: |
                  const b = var(--prime-video-icon);
                  b; 

            card:
              type: custom:button-card
              entity: []
              show_entity_picture: true
              #entity_picture: "/local/images/prime-video2-white-cropped.svg"
              entity_picture: ${ICON} 
              name: ${a}

There is absolutely no need to use config-template-card for custom button-card (which supports JS natively) . You are just adding more glitches.
And in JS you need to put css variables in quotes.