Custom:smart-grid layout card

Just finished my first custom layout card. Don’t ask me how I did it, but somehow, it seems I got it working…

The card is very similar to the grid card, except that in portrait mode, all the columns collapse into one. This simple change enables layouts that look nice in both portrait and landscape modes (and thus also in desktop mode).

Here is a little example of how it looks on my phone:


The custom card is based on the built in grid card and uses the same config entries. So, it is possible to replace any grid card simply by exchanging ‘type:grid’ with ‘type: custom:smart-grid’. To edit the card content with the graphical editor, it’s also possible to temporarily switch it back to ‘type: grid’ and use the grid card’s graphical editor.

Here is the source if you are interested :

smart-grid.js
import {
  LitElement,
  html,
  css,
} from "https://unpkg.com/[email protected]/lit-element.js?module";

class AspectRatioColumnsLayout extends LitElement
{
  async setConfig( config )
  {
    if ( !config || !config.cards || !Array.isArray(config.cards) )
      throw new Error( "Invalid configuration" );

    if ( config.columns )
      this.style.setProperty( "--max-cols", String(config.columns) );
    else
      this.style.removeProperty( "--max-cols" );

    if ( config.square )
      this.setAttribute( "square", "" );
    else
      this.removeAttribute( "square" );

    window.loadCardHelpers().then( (cardHelpers) => {
      this.elements = config.cards.map( (cardConfig) => { return cardHelpers.createCardElement( cardConfig ); } );
    } ).then( this.requestUpdate() );

    //console.log( [this] );
  }

  static get properties()
  {
    return {
      elements: {type: Array, attribute: false},
      hass: {type: Object, attribute: false}
    };
  }

  updated( changedProps )
  {
    super.updated( changedProps );
    //console.log( changedProps );

    if ( !this.elements ) return;

    //if ( changedProps.has("hass") )
      this.elements.forEach( (e) => { e.hass = this.hass; } );
  }

  render()
  {
    if( !this.elements ) return html``;
    return html`<style>
      @media (max-aspect-ratio: 11/10)
      {
        #root { grid-template-columns: 1fr !important; }
      }
      /* #root div { background: #9ff; } */
      #root
      {
        display: grid;
        grid-template-columns: repeat( var(--max-cols,2), minmax(0, 1fr) );
        grid-gap: var(--grid-card-gap, 8px);
      }
      :host([square]) #root {
        grid-auto-rows: 1fr;
      }
      :host([square]) #root::before {
        content: "";
        width: 0;
        padding-bottom: 100%;
        grid-row: 1 / 1;
        grid-column: 1 / 1;
      }
      :host([square]) #root > *:not([hidden]) {
        grid-row: 1 / 1;
        grid-column: 1 / 1;
      }
      :host([square]) #root > *:not([hidden]) ~ *:not([hidden]) {
        grid-row: unset;
        grid-column: unset;
      }
</style> <div id="root">${this.elements.map((card) => html`<div>${card}</div>`)}</div>`;
  }

}

customElements.define("smart-grid", AspectRatioColumnsLayout );
4 Likes

Another example with 3 columns:

1 Like

Hey there, this really looks awesome! Could you please elaborate how to set this custom component up?

Bests!

Thanks!

There is a guide here that explains how to install a custom card from source : https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card/

Then, once you got the module installed in Home Assistant, you can start experimenting with it. To get started I’d suggest this procedure: Place a new card (any type), switch to code editor, select all and paste the example code below.

type: custom:smart-grid
columns: 2
cards:
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Warnemuende-NW/Warnemuende-NW_latest_640.jpg
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Wasserkuppe-SW/Wasserkuppe-SW_latest_640.jpg
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Lindenberg-NNE/Lindenberg-NNE_latest_640.jpg
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Hamburg-SO/Hamburg-SO_latest_640.jpg
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Hohenpeissenberg-S/Hohenpeissenberg-S_latest_full.jpg
  - type: picture
    image: >-
      https://opendata.dwd.de/weather/webcam/Hamburg-SW/Hamburg-SW_latest_640.jpg
1 Like