Flex-table-card

New data fields including device_manufacturer are now available in the latest release.

See the updated docs:
Examples - Column Data Selector

The platform of an entity is now available in the latest release.

See updated docs:
Examples - Column Data Selector

The documentation now explains how auto-refresh can work for cards that are fed by actions and scripts rather than directly by entities. It’s under Loading from Actions and Scripts beginning here.

Have had a fair search (and will continue to do so) but has anyone got an existing method of pulling a sensor’s attribute for a column header?

Whilst I’ve got a bunch of sensors to fill the table - sensor.sa_cfs_* with a region’s name for the asterisk, each of those regions have a value for day_x_date.

This is the same across all of the regions, but I’ve also got it pulling into the master ‘aggregated’ sensor, so could specify it off that - eg sensor.sa_cfs_firedanger.day_1_date.

Thinking I’ll need to use card_mod so will have more of a search after this… and document the stream of consciousness.

EDIT: Worked it out - wrapped inside a config-template-card.
The whole card’s code below, although the Day Name is currently redundant.

type: custom:config-template-card
variables:
  DAY1_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_1_name
  DAY2_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_2_day_name
  DAY3_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_3_day_name
  DAY4_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_4_day_name
  DAY5_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_5_day_name
  DAY1_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_1_date
  DAY2_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_2_date
  DAY3_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_3_date
  DAY4_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_4_date
  DAY5_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_5_date
entities:
  - sensor.sa_cfs_fire_danger
card:
  type: custom:flex-table-card
  title: SA CFS Fire Danger Ratings
  entities:
    include: sensor.sa_cfs*
    exclude: sensor.sa_cfs_fire_danger
  columns:
    - data: region_name
      name: Region
    - data: day_1_rating
      name: Today
      align: center
      modify: |-
        if (x == "No Rating")
          "No Rating"
        else if (x == "Moderate")
          '<div style="background-color:#35C300;">Moderate</div>'
        else if (x == "High")
          '<div style="background-color:#FFDD00;">High</div>'
        else if (x == "Extreme")
          '<div style="background-color:#FF7A00;">Extreme</div>'
        else if (x == "Catastrophic")
          '<div style="background-color:#BD0000;color:#FFFFFF;">Catastrophic</div>'
        else x
    - data: day_1_fbi
      name: ""
      align: center
    - data: day_2_rating
      name: Tomorrow
      align: center
      modify: |-
        if (x == "No Rating")
          "No Rating"
        else if (x == "Moderate")
          '<div style="background-color:#35C300;">Moderate</div>'
        else if (x == "High")
          '<div style="background-color:#FFDD00;">High</div>'
        else if (x == "Extreme")
          '<div style="background-color:#FF7A00;">Extreme</div>'
        else if (x == "Catastrophic")
          '<div style="background-color:#BD0000;color:#FFFFFF;">Catastrophic</div>'
        else x
    - data: day_2_fbi
      name: ""
      align: center
    - data: day_3_rating
      name: ${DAY3_DATE}
      align: center
      modify: |-
        if (x == "No Rating")
          "No Rating"
        else if (x == "Moderate")
          '<div style="background-color:#35C300;">Moderate</div>'
        else if (x == "High")
          '<div style="background-color:#FFDD00;">High</div>'
        else if (x == "Extreme")
          '<div style="background-color:#FF7A00;">Extreme</div>'
        else if (x == "Catastrophic")
          '<div style="background-color:#BD0000;color:#FFFFFF;">Catastrophic</div>'
        else x
    - data: day_3_fbi
      name: ""
      align: center
    - data: day_4_rating
      name: ${DAY4_DATE}
      align: center
      modify: |-
        if (x == "No Rating")
          "No Rating"
        else if (x == "Moderate")
          '<div style="background-color:#35C300;">Moderate</div>'
        else if (x == "High")
          '<div style="background-color:#FFDD00;">High</div>'
        else if (x == "Extreme")
          '<div style="background-color:#FF7A00;">Extreme</div>'
        else if (x == "Catastrophic")
          '<div style="background-color:#BD0000;color:#FFFFFF;">Catastrophic</div>'
        else x
    - data: day_4_fbi
      name: ""
      align: center
grid_options:
  columns: 24

I have a table, that is populated via row expansion from a list, as described in the docs:

Card-Config:

type: custom:flex-table-card
entities:
  include: sensor.recorder_top_events
columns:
  - data: json
    modify: x.entity_id
    name: Entity ID
  - data: json
    modify: x.count
    name: Events/Tag

Content of sensor.recorder_top_events:

{
  "json": [
    {
      "entity_id": "sensor.stromzahler_leistung_momentan",
      "count": 17235
    },
    {
      "entity_id": "sensor.steckdosenleiste_spannung",
      "count": 14869
    },
[...]
  ],
  "unit_of_measurement": "events",
  "friendly_name": "Recorder Top Events"
}

I’m now struggeling with making the first column clickable to show the more info dialog for the respective entity id.

Just

tap_action:
  action: more-info

isn’t working, because this only shows the more info dialog for the source entity (sensor.recorder_top_events), but not the entities in the list.

How do I achieve this?

The more-info action currently uses the “row entity”, which in this case is sensor.recorder_top_events for all rows, and this cannot be overridden. But it should.

If you want to edit the card Javascript in flex-table-card.js, it’s a one line change.

Change Line 920 (in function _handle_more_info) from:
entity: row.entity.entity_id,
to:
entity: getRefs(col[action_type].entity, row.data, elem.cells) || row.entity.entity_id,

Then your card definition changes to:

type: custom:flex-table-card
entities:
  - sensor.recorder_top_events
columns:
  - data: json.entity_id
    name: Entity ID
    tap_action:
      action: more-info
      entity: cell[0]
  - data: json.count
    name: Events/Tag

Note that you don’t need the modify tag.

And if you don’t mind, go to the repository and open a feature request under Issues to request this feature.

1 Like

Also, if you make this change on your own system, you need to delete the .gz file for the .js file to load. By default, the system pulls in the .gz if it exists.

And probably restart HA.

In my case I’ve manually copied the .js file over to the www folder, so all I have to do is alter the version number in Dashboard/Resources and refresh the browser.

Actually, I only read @EdLeckert’s reply in the notification mail, thus missed your comment, was puzzled by this behavior and was just about to reply the same thing after I found out about this. :smile:

(…and to be honest, this wasn’t the first time, I forgot about this…)

1 Like

Thank you, that’s working fine. I’ll open the feature request for this. :+1:

Thanks. A PR to support this has been submitted.

Can someone point me to an example that allows a single sensor’s attributes to be displayed in rows; so the attribute name is column 1 and the attribute value is column 2, 3, 4, etc. If it matters, the attributes are a single JSON output with the structure

data:

  • name: Category 1
    budget_value: 118.63
    spend_value: -118.63
    balance: 0
  • name: Category 2
    budget_value: 1500
    spend_value: -239.89
    balance: 1260.11
  • name: …

Thanks

This one?

If the sensor has a single attribute named data containing the array of categories, then this column definition will work:

type: custom:flex-table-card
entities: []
columns:
  - name: Category
    data: data.name
  - name: Budget
    data: data.budget_value
  - name: Spend
    data: data.spend_value
  - name: Balance
    data: data.balance
static_data:
  data:
    - name: Category 1
      budget_value: 118.63
      spend_value: -118.63
      balance: 0
    - name: Category 2
      budget_value: 1500
      spend_value: -239.89
      balance: 1260.11

I’ve used static data for this example.

If you have a separate attribute for each category, I don’t believe it would work. You’d have to create a new template entity and store the list of categories under a single attribute so the card could iterate through the list.

Hi guys,

I want to build a table to diagnose the state of my Matter over Thread devices.

I envision the following structure:

  • only devices of the Matter integration are part of the table
  • every device of the Matter integration gets its own line in the table
Device name Area Brand/model Firmware Hardware Serial number Node ID Network type Device type Network name MAC address IP address(es) State State unavailable 1h State unavailable 1d State unavailable 1w State unavailable 1m
Abstellkammer Bewegung Abstellkammer Eve Motion 20EBY9901 (89) by Eve Systems 3.2.1 1.1 ZV38L1Axxxxx 11 Thread Sleepy end device MyHome16481xxxxx aa:0f:2f:1c:51:b1:xx:xx fd10:ca04:cd19:0:xxxx:xxx:xxxx:xxxx available 0 0 0 0
Büro Spot 1 Büro LED Bulb T2 (GU10, RGB CCT) (6149) by Aqara 1.0.0.0 1.0.0.0 4EF4410010xxxxx 327 Thread End device MyHome16481xxxxx 1a:0d:85:7f:e4:90:xx:xx fd10:ca04:cd19:0:xxxx:xxx:xxxx:xxxx available 0 0 0 1
Büro Radar Büro LWR01 (40961) by GL Technologies 1.0.0 1.0.0 d8505a4bf5fxxxxx 358 Thread Sleepy end device MyHome16481xxxxx 7a:27:48:8b:76:d2:xx:xx fd10:ca04:cd19:0:xxxx:xxx:xxxx:xxxx available 0 0 0 2
Wohnbereich Aquarium Wohnbereich Eve Energy 20EBO8301 (80) by Eve Systems 3.5.0 1.1 RV39L1Axxxxx 330 Thread Routing end device MyHome16481xxxxx 1e:9d:db:3f:5f:5e:xx:xx fd10:ca04:cd19:0:xxxx:xxx:xxxx:xxxx unavailable 1 4 17 36

The data is almost there, but not in this compressed form.

Most information can be found in the device info:

The real magic happens in the last 5 columns:

  1. State = any entity of the device can be used (if state != unavailable, than state available)
  2. State unavailable 1h = unavailable counter for the last hour
  3. State unavailable 1d = unavailable counter for the last day
  4. State unavailable 1w = unavailable counter for the last week
  5. State unavailable 1m = unavailable counter for the last month

What do you think?
Is this something that can be achieved with Flex-table-card?
If not, any idea what table tool I need to achieve this?

I am not a developer. :wink:

Thanks Hoppel

I do something like that with a markdown card and a template

happy to share the template if that would be something you could use

check here how we built that

This is quite the project! Here are some thoughts.

As is often the case with showing complex data in flex-table-card, a template or templates could be created to pre-process the data into a form that the card can use. You could create a template entity for each device or a single entity that can discover the devices, using language like this example to find all Z-Wave devices:

{% for device in integration_entities('zwave_js') | map('device_id') | unique | list %}
{{ device_attr(device, "name") -}}
{% endfor %}

You could then use device_attr in the loop to get the standard device properties:

{{ device_attr(device, "name_by_user") }}
{{ area_name(device_attr(device, "area_id")) }}
{{ device_attr(device, "manufacturer") }}/{{ device_attr(device, "model") }}
{{ device_attr(device, "sw_version") }}
{{ device_attr(device, "hw_version") }}
{{ device_attr(device, "serial_number") }}

The extended device properties available for Matter and Z-Wave devices (under the Device info dropdown in your screenshot) do not seem to be available except via a websocket call, so I don’t that’s going to work.

To get the current availability or any other value available as an entity, you’d need to find an entity that’s available on each device. This crude example gets the state from an entity on each device (e.g. sensor.front_porch_light_last_seen) and whether it was contacted in the last hour:

{% for device in integration_entities('zwave_js') | map('device_id') | unique | list %}
{{ device_attr(device, "name_by_user") }}
{%- for entity in device_entities(device) %}
{%- if "last_seen" in entity %}
{% if states(entity) not in ("unknown", "unavailable") -%}
available
{{ as_timestamp(now()) - as_timestamp(states(entity)) > 3600 -}}
{% else %}
unavailable
{% endif -%}
{% endif -%}
{% endfor %}
{% endfor %}

Media Room Sconces
available
True

TV LEDs
available
False

Getting a count of the number of times unavailable over various periods would be a more advanced topic involving automations and perhaps input_number helpers.

Finally, if you create a single template entity, it needs to return a format that flex-table-card can digest, not just displayed simply as in the above examples. See the myfamily structure in the docs for an example.

My advice is to start simply. Perhaps just find an entity from each device and load the card with those. You can then get the standard device attributes directly from the card.

Good luck!

1 Like

Sorry, if I missed it in the docs: How can I add the friendly_name to each row when I have a list of attributes that I want to get expanded?
Use case is from db-infoscreen, I have two sensors holding depature times as attributes, but the station is stored in the entity

What I want, is that each departure is a row, with each holding the station too

db-infoscreen data
next_departures:
  - countdown: "8"
    datetime: 1767081960
    delay: "0"
    destination: Eppelheim, Kirchheimer Straße
    hints: []
    is_cancelled: 0
    line: "22"
    origin: Heidelberg, Bismarckplatz
    platform: B
    platform_name: Bstg. B
    platform_type: Bstg
    rt_datetime: 1767081960
    sched_datetime: 1767081960
    type: Straßenbahn
    trainClasses:
      - a
      - r
      - ß
      - e
      - t
      - "n"
      - h
      - S-Bahn
      - b
    departure_current: "09:06"
    departure_timestamp: 1767081960
    arrival_current: "09:06"
    arrival_timestamp: 1767081960
  - countdown: "9"
    datetime: 1767082020
    delay: "0"
    destination: Heidelberg, Bismarckplatz
    hints: []
    is_cancelled: 0
    line: "22"
    origin: Eppelheim, Kirchheimer Straße
    platform: A
    platform_name: Bstg. A
    platform_type: Bstg
    rt_datetime: 1767082020
    sched_datetime: 1767082020
    type: Straßenbahn
    trainClasses:
      - a
      - r
      - ß
      - e
      - t
      - "n"
      - h
      - S-Bahn
      - b
    departure_current: "09:07"
    departure_timestamp: 1767082020
    arrival_current: "09:07"
    arrival_timestamp: 1767082020
  - countdown: "10"
    datetime: 1767082080
    delay: null
    destination: Ziegelhausen, Köpfel
    hints: []
    is_cancelled: 0
    line: "36"
    origin: Pfaffengrund, Kranichweg/Stotz
    platform: D
    platform_name: Bstg. D
    platform_type: Bstg
    sched_datetime: 1767082080
    type: Bus
    trainClasses:
      - u
      - B
      - s
    departure_current: "09:08"
    departure_timestamp: 1767082080
    arrival_current: "09:08"
    arrival_timestamp: 1767082080
  - countdown: "18"
    datetime: 1767082560
    delay: null
    destination: Ziegelhausen, Köpfel
    hints: []
    is_cancelled: 0
    line: "36"
    origin: Pfaffengrund, Kranichweg/Stotz
    platform: E
    platform_name: Bstg. E
    platform_type: Bstg
    sched_datetime: 1767082560
    type: Bus
    trainClasses:
      - u
      - B
      - s
    departure_current: "09:16"
    departure_timestamp: 1767082560
    arrival_current: "09:16"
    arrival_timestamp: 1767082560
station: Kranichweg/Stotz, Pfaffengrund
via_stations: []
direction: ""
last_updated: "2025-12-30T08:58:21.329579"
attribution: >-
  Data provided by API
  https://dbf.finalrewind.org/Kranichweg%2FStotz,%20Pfaffengrund.json?efa=VRN
icon: mdi:train
friendly_name: Kranichweg/Stotz, Pfaffengrund Departures

As I am not a programmer I am struggling to understand, if it is at all achievable what I want to do.

I use flex table card to have all upcoming energy prices to see at a glance, when it is the best time to charge the car, the home battery, etc.:

I was rather happy with this table when the price changed only every hour: The maximum no. of rows was 36 … since having quarterly energy prices the number of rows quadrupled and the table become unhandy.

I want to change the layout into something more heat-map like to reduce the number of rows:


… but all my attempts did not even bring me close to this :frowning:

The data is coming from a sensor with following attributes - not quite sure, if this is what the professionals call an “array”:

The code for the card looks currently straight forward:
type: custom:flex-table-card
title: Tibber - Strompreise
entities:
  include: sensor.electricity_price
sort:
  - future
columns:
  - name: Sorting columns
    data: future
    modify: x.startsAt
    hidden: true
  - name: Ab
    data: future
    modify: |
      {
        var colors = [
            { level: "VERY_EXPENSIVE",  color: "red" },
            { level: "EXPENSIVE",       color: "goldenrod" },
            { level: "NORMAL",          color: "" },
            { level: "CHEAP",           color: "lightgreen" },
            { level: "VERY_CHEAP",      color: "limegreen" } ]
        var startsAt = new Date(x.startsAt)
        var d = new Date()
        var sday = ""
        if (startsAt.getDay() == d.getDay())
          sday = "Heute"
        else
          sday = "Morgen";
        '<div style="color: black; background-color: ' + colors.find(c => c.level === x.level).color + '">'
          + sday + ", " + startsAt.getHours().toLocaleString('de-DE', {minimumIntegerDigits: 2}) + ":" + startsAt.getMinutes().toLocaleString('de-DE', {minimumIntegerDigits: 2}) + " Uhr" + 
        '</div>'
      }
  - name: Arbeitspreis
    data: future
    modify: |
      {
        var colors = [
            { level: "VERY_EXPENSIVE",  color: "red" },
            { level: "EXPENSIVE",       color: "goldenrod" },
            { level: "NORMAL",          color: "" },
            { level: "CHEAP",           color: "lightgreen" },
            { level: "VERY_CHEAP",      color: "limegreen" } ]
        '<div style="color: black; background-color: ' + colors.find(c => c.level === x.level).color + '">'
            + x.total.toFixed(4)
      }
  - name: Strompreis
    data: future
    modify: |
      {
        var colors = [
            { level: "VERY_EXPENSIVE",  color: "red" },
            { level: "EXPENSIVE",       color: "goldenrod" },
            { level: "NORMAL",          color: "" },
            { level: "CHEAP",           color: "lightgreen" },
            { level: "VERY_CHEAP",      color: "limegreen" } ]
        '<div style="color: black; background-color: ' + colors.find(c => c.level === x.level).color + '">'
            + x.energy.toFixed(4)
      }
    align: right

Can I achieve this with the flex table card and - if yes - can someone point me into the right direction? Thanks!

Hello.

Is it possible to call an action/service by pressing a html button instead of a table cell?

I mean, having such a code:

- name: ""
    modify: "<div>some html or text </div><button class='button'>Dismiss</button>"

I would like to call action by pressing the button, passing x.identifier as an argument.

Here is a usecase I would like to cover: