Creating custom cards for Home Assistant

Creating custom cards for Home Assistant

The goal of this post is to give you a brief introduction to creating custom cards for Home Assistant using Lit elements, and I will share with you takeaways from my experience learning how to create custom cards for Home Assistant.

Home Assistant is a powerful, open-source, extensible (and much more) platform for home automation. If you are using it, You probably are a fan of the dashboards, and the cards are one of the most important parts of it.

Even if Home Assistant provides a lot of built-in cards, sometimes you need something more specific or with a graphical style, because dashboards are not only to display an infinite list of numbers or charts, the information must be displayed hierarchically.

HACS (Home Assistant Community Store) provides an easy way to install Home Assistant custom elements (not only cards, but also integration, themes, etc.) created by the community. If you are looking for a simple way to customize your Home Assistant’s dashboard, HACS, is the way to go. These cards are usually very configurable, but in some cases or for certain users, that configuration may not be enough.

For these cases, there is a project in HACS like button-card that allows you to add styles, cards in cards, etc, just using a YAML configuration. That is quite nice, but reusing the cards means you need to copy and paste the card code and change the “variables”, but when you do a change in the style or add a new element, you need to copy the code again manually.

If you are familiar with YAML, maybe you think you could use yaml fragment to reuse parts of the code, but that is not possible in ‘UI controlled’ dashboards.

UI controlled vs YAML dashboards

In Home Assistant, there are two types of dashboards: UI controlled and YAML-controlled. The UI controlled dashboards are the default ones, and they are configurable using the Home Assistant UI, you can drag and drop the cards to change the position, use the interface to edit the configuration of the card, etc. But even if you can export the configuration to YAML, you cannot use YAML fragments to reuse code. If you do it at Home Assistant will apply the fragments and flatten the configuration to store it in the internal database, not in a real file, so the next time you want to edit the dashboard, YAML fragments will not be available.

The YAML-controlled dashboards are more flexible; you can use YAML fragments and templates to reuse the code, but you lose the simplicity of the UI, also, even using Jinja2 templates, in my opinion, is not flexible enough.

Custom cards in Home Assistant

Custom elements

Home Assistant allows you to create custom cards just using Web Components, a web standard that allows you to create reusable components using HTML, CSS, and JavaScript.

Defining a custom element is as simple as creating a class that extends the HTMLElement class and defining the create DOM nodes you need

class MessageCard extends HTMLElement {
  constructor() {
    super();
    this.message = this.getAttribute("message");
    this.template = document.createElement("template");
    this.template.innerHTML = `      
      <h1 class="message">${this.message}</h1>`;
    this.shadow = this.attachShadow({ mode: "open" });
    this.shadow.appendChild(this.template.content.cloneNode(true));
  }  
}

To use it you must register it

customElements.define("message-card", MessageCard);

And then you can use it in your HTML as a normal HTML element.

<message-card message="Hello world"></message-card>

Using a custom element as a custom card in Home Assistant

To use a custom element as a custom card in Home Assistant, you need to register it using a global variable.

window.customCards = window.customCards || []
window.customCards.push({
  type: 'message-card', // This is the name you registered the custom element with
  name: 'Message Card',
  description: 'This is my first HA custom card',
})

And now we need to make this js code available to Home Assistant, for that, we need to add it as a resource in the dashboard Edit dashboard > Manage resources > Add resource and add the path to the JS file. You could use external hosting and load the resource from it, e.g. http://mypage/custom-card.js, but don’t do it as is risky in terms of security, and you depend on the internet connection to show the cards.

The best way is to use the www folder in your Home Assistant installation, you can find it in the root of your Home Assistant installation. You can create a folder inside www to store your custom cards and store the card file there, for example /www/my-custom-cards/message-card.js

Note that the path in the “manage resource” page is relative to the www folder, so you need to add /local/ before the path to the file, so in this case you must use /local/my-custom-cards/message-card.js as the resource path.

You can also use HACS to distribute and install your custom cards, HACS will take care of adding the resource to the dashboards, but this is out of the scope of this post.

Lit elements

Creating custom elements using the HTMLElement class is a bit tedious; you need to create the DOM nodes manually, and handle all the event changes in the status, etc, by yourself.

As Home Assistant custom cards are just a custom element, you can use any framework to create it, for example, Vue, React ( since v19), Angular, etc., but Home Assistant uses Lit elements in the frontend, so it is a good idea to use this lightweight library, and nice to create your custom cards.

I should mention before that Home Assistant will try to pass some properties to the custom element and expects some methods, to pass and get information about your card.

  • Whenever the state changes, update the attribute hass with an object that includes the state of the Home Assistant instance, sensors, areas, etc.
  • It will call the function setConfig(config) to pass the configuration of the card

There are more properties and methods that Home Assistant will call, but the most important are those two. You can check the official documentation

An example of a custom card using Lit elements is the following one, which gets a list of entity IDs from the configuration and returns a list of the friendly names of the entities.

class MyCard extends LitElement {
  static get properties () {
    return {
      hass: {},
      config: {},
    };
  }

  render () {
    return html`
      <ha-card title="My Card">
        ${this.config.entities.map((ent) => {
      const stateObj = this.hass.states[ent];
      return stateObj
        ? html`
                <div class="state">
                  ${stateObj.attributes.friendly_name}                  
                </div>
              `
        : html` <div class="not-found">Entity ${ent} not found.</div> `;
    })}
      </ha-card>
    `;
  }

Using custom elements from Home Assistant in your custom cards

In the previous example, you probably noticed that I used the ha-card element, which is a custom element provided by Home Assistant that renders a card container.

Home Assistant provides other custom elements that you can use in your custom cards, for example, ha-icon, ha-icon-button, ha-dialog, etc.

I think it is a good idea to use the custom elements provided by Home Assistant in your custom cards to create a consistent card with the rest of the Home Assistant cards.

You can find them in the frontend repo

Unfortunately, not all the custom elements are loaded by default, but you can use the package @kipk/load-ha-components (See it on GitHub) to force load the custom elements you need in your custom card.

Custom cards helpers

As with any other web project, I recommend you use TypeScript to create your custom cards, and you can use your favorite tools to transpile and bundle the code, but in this case, I strongly recommend you to use Custom cards helpers, a library that provides some helpers and a lot of types to create custom cards.

Resources

There are a lot of resources to learn how to create custom cards for Home Assistant, but they are not always easy to find. I want to share with you some links I found, while I was learning how to create custom cards, so that you avoid wasting that time and investing in more useful things.

My first custom card

img.png

I want to share with you my first custom card, which I created to show the status of a room in my house. The card shows the temperature, humidity, and the summary of the status of the devices in the room by type, for example, the number of lights on, whether there is a presence or not in the room. It also allows defining alarm entities, which will be shown as alarms in the card. (e.g a smoke detector)

https://github.com/sergiocarracedo/sc-custom-cards

It can also be used as a header card to show the room name and a summary of the devices in that room is a subdashboard.

img_1.png