
Last updated on February 04, 2026
Let’s continue our deep dive into the awesome capabilities of the Home Assistant Button Card. In this updated guide for 2026, we’re going to build two cards that are staples for any serious Home Assistant dashboard: one for monitoring percentage-based sensors and another for displaying complex device states. If this is your first time working with this card, I highly recommend you read the initial setup guide, as it lays the foundation for everything we’ll do here.
The first card will dynamically change its icon and color based on a battery’s charge level—a technique that works for any sensor that reports a percentage, like a smart blind’s openness or a water tank level. The second card is a more advanced example of smart home automation: it will show a light’s status while simultaneously displaying the temperature from a completely different entity, all in a compact, custom design powered by CSS Grid.
Building a Dynamic Battery Card with Home Assistant Button Card
The goal here is at-a-glance sensor monitoring that’s both visual and intuitive. We want one look to tell us everything we need to know about a device’s battery. We’ll be using JavaScript templates directly in our YAML to make the icon color shift from green to red as the level drops, and to have the icon itself reflect the remaining charge.
Here’s the code you’ll need. Just remember to replace sensor.t671h_battery_level with your own sensor’s entity ID.
type: custom:button-card
entity: sensor.t671h_battery_level
name: Phone Battery
show_state: true
styles:
card:
- border-radius: 15px
- border: 2px solid var(--primary-text-color)
- background-color: var(--ha-card-background, var(--card-background-color, #1c1c1c))
name:
- color: var(--primary-text-color)
- font-weight: bold
state:
- font-weight: bold
- color: var(--secondary-text-color)
grid:
- grid-template-areas: '"n" "i" "s"'
icon:
- color: |
[[[
const state = entity.state;
if (state < 10) return "var(--error-color)";
if (state < 20) return "var(--warning-color)";
if (state < 40) return "yellow";
return "var(--success-color)";
]]]
icon: |
[[[
const state = Math.round(entity.state / 10) * 10;
if (entity.state > 95) return "mdi:battery";
if (state == 0) return "mdi:battery-outline";
if (isNaN(state)) return "mdi:battery-unknown";
return "mdi:battery-" + state;
]]]
Code Breakdown:
- styles: For this 2026 version, I’ve replaced hard-coded colors (like
rgb(255,255,255)) with Home Assistant theme variables (e.g.,var(--primary-text-color)). This makes your card automatically adapt to your light and dark themes—a must-have for modern dashboards. - grid: We’re using
grid-template-areasto define a simple three-row layout: name (n), icon (i), and state (s). - icon color: The JavaScript logic evaluates the entity’s state (
entity.state). Based on the value, it returns a different color. I’ve simplified the logic and used system color variables for seamless integration. - icon: Similarly, another JavaScript template selects the most appropriate icon from Material Design Icons. I’ve optimized this code to be more compact and efficient than the long chain of
ifstatements you might see in older examples.
Advanced State Display: Combining a Light and Temperature Sensor
Now, let’s take it a step further and create some truly custom UI elements. This card not only shows if a light is on or off but also cleverly uses a corner space to display a temperature reading, creating a multifunctional information widget.
The key here is a more complex use of the CSS grid to position each element with precision. Be sure to swap light.sofa and sensor.living_room_temperature with your own entities.
type: custom:button-card
entity: light.sofa
name: Sofa
icon: mdi:sofa
show_state: false
styles:
card:
- border-radius: 20px
grid:
- grid-template-areas: '"i temp" "n temp"'
- grid-template-columns: 1fr auto
- grid-template-rows: 1fr auto
icon:
- color: |
[[[
return entity.state === 'on' ? 'var(--paper-item-icon-active-color)' : 'var(--paper-item-icon-color)';
]]]
custom_fields:
temp: |
[[[
const temp_entity = states['sensor.living_room_temperature'];
if (temp_entity) {
return `<ha-icon
icon="mdi:thermometer"
style="width: 18px; height: 18px; color: var(--secondary-text-color);">
</ha-icon>
<span style="color: var(--primary-text-color); font-size: 14px;">
${Math.round(temp_entity.state)}°C
</span>`
}
return '';
]]]
Code Breakdown:
- grid: The
grid-template-areas: '"i temp" "n temp"'configuration creates a 2×2 grid. The icon (i) and name (n) occupy the first column, while our custom temperature field (temp) spans both rows of the second column. - icon color: A simple JavaScript ternary operator assigns the active color if the light is
onand the default color if it’soff. Clean and efficient. - custom_fields: This is where the magic happens.
- We define a field named
temp. - Inside, the JavaScript accesses the state of a completely different entity (
states['sensor.living_room_temperature']). - It then builds an HTML snippet that includes an icon and the rounded value from the sensor. This is an incredibly powerful technique for combining information in your Lovelace UI.
- We define a field named
Common Issues & FAQ
Even with the perfect config, sometimes things don’t go as planned. Here are the solutions to the most common problems.
| Problem | Solution |
| My card doesn’t appear or shows a red error box. | First, make sure Button Card is installed correctly via HACS. Go to Settings > Dashboards > 3-dot menu > Resources and verify the path to button-card.js exists. Finally, triple-check your YAML indentation; it is the #1 cause of errors. |
| The color or icon isn’t changing dynamically. | Check the syntax inside your [[[ ... ]]] templates. A common mistake is using single quotes inside a string that’s already enclosed in single quotes. Also, check the actual state of your entity in Developer Tools to make sure it matches what you’re expecting in your logic (e.g., that a battery sensor is returning a number and not “Unknown”). |
| Can I use this card to run services or automations? | Absolutely! While this guide focuses on visuals, you can add a tap_action option to define what happens when you press the card, like calling a service (action: call-service), navigating to another view (action: navigate), or more. It’s the key to creating truly interactive controls. |
