🔹 Layout-card - Take control of where your cards end up

Try grid layout and define the columns

     - type: custom:layout-card
       layout_type: custom:grid-layout
       layout:
          grid-template-columns: 1fr 1fr
       cards:
          - type:

I have been trying for a while to make my 3 columns custom sizes.
I’ve tried with the dashboard layout set to Panel, masonry(layout-card) and grid(layout-card).

I’ve tried with the card in the dashboard being custom:masonry-layout and custom:grid-layout

I’ve tried setting the grid-template-columns to pixels, percents and fr. Whatever I do all 3 columns continue to be the exact same size as each other. I don’t understand what I’m doing wrong.

Here is the code I have currently, hoping someone can help me.:

type: custom:layout-card
layout_type: custom:grid-layout
layout:
  width: 1250
  max_cols: 3
layout_options:
  grid-template-columns: 350px 450px 450px
  grid-template-rows: auto
  grid-template-areas: |
    "left middle right"
cards:
  - type: vertical-stack
    cards:
      - square: false
        type: grid
        cards:
          - type: vertical-stack
            view_layout:
              grid-area: left
            cards:
              - type: entity
                entity: sensor.sun_next_dawn
                name: Next Dawn
              - type: entity
                entity: sensor.sun_next_dusk
                name: Next Dusk
          - type: vertical-stack
            view_layout:
              grid-area: middle
            cards:
              - show_state: true
                show_name: true
                camera_view: live
                type: picture-entity
                entity: camera.front_porch_camera
                image: >-
                  http://192.168.0.0/ISAPI/Streaming/channels/101/picture?snapShotImageType=JPEG
                name: Front Porch Camera
                camera_image: camera.front_porch_camera
              - show_state: true
                show_name: true
                camera_view: live
                type: picture-entity
                entity: camera.north_yard_camera
                image: >-
                  http://192.168.0.0/ISAPI/Streaming/channels/201/picture?snapShotImageType=JPEG
                name: North Yard Camera
                camera_image: camera.north_yard_camera
          - type: vertical-stack
            view_layout:
              grid-area: right
            cards:
              - show_state: true
                show_name: true
                camera_view: live
                type: picture-entity
                entity: camera.back_yard_camera
                image: >-
                  http://192.168.0.0/ISAPI/Streaming/channels/401/picture?snapShotImageType=JPEG
                name: Back Yard Camera
                camera_image: camera.back_yard_camera
              - show_state: true
                show_name: true
                camera_view: live
                type: picture-entity
                entity: camera.south_yard_camera
                image: >-
                  http://192.168.0.0/ISAPI/Streaming/channels/301/picture?snapShotImageType=JPEG
                name: South Yard Camera
                camera_image: camera.south_yard_camera
        columns: 3

EDIT: I also tried this layout without the initial vertical stack and without the initial grid card. Nothing I do changes it from 3 equal columns

EDIT: also tried no vertical stack or grid, just the grid layout-card with 3 entity cards in it, marked with the proper grid areas. Still either had 3 equal columns or just 1 column. I don’t get it.

For the life of me I can’t seem to change the color of the background on the custom layout card that contains the other cards within it. Feels like I’m missing something very simple but I’ve spent hours with no luck. Anyone have any idea what I’m doing wrong? Excuse the poor mark-up, I’m working off a laptop.

  - title: test
    type: custom:horizontal-layout
    cards:
      - type: custom:layout-card
        layout_type: custom:masonry-layout
        layout:
          width: 150
          max_cols: 2
        cards:
          - type: custom:stack-in-card
            cards:
              - type: custom:mushroom-template-card
                primary: Main Gym Door
                secondary: |-
                  {% if is_state('binary_sensor.main_gym_door','on') %}
                    Door Open
                  {% elif is_state('lock.main_gym','unlocked') %}
                    Unlocked
                  {% else %}
                    Locked
                  {% endif%}
                icon: |-
                  {% if is_state('binary_sensor.main_gym_door','on') %}
                    mdi:door-open
                  {% elif is_state('lock.main_gym','unlocked') %}
                    mdi:lock-open
                  {% else %}
                    mdi:lock
                  {% endif%}
                icon_color: >-
                  {% if is_state('lock.main_gym','locked') and
                  is_state('binary_sensor.main_gym_door','off') %}
                    red
                  {% elif is_state('binary_sensor.main_gym_door','on') %}
                    yellow
                  {% else %}
                    green
                  {% endif%}
                badge_icon: >-
                  {% set battery_level = (states('sensor.main_gym_battery') |
                  int / 10) | round(0) | int * 10 %} {% if battery_level == 100
                  %} mdi:battery {% elif battery_level > 0 %} mdi:battery-{{
                  battery_level }} {% else %} mdi:battery-alert-variant-outline
                  {% endif %}
                badge_color: >-
                  {% set battery_level = states('sensor.main_gym_battery') | int
                  %}

                  {% if battery_level > 90 %} green

                  {% elif battery_level > 60 %} light-green

                  {% elif battery_level > 50 %} lime

                  {% elif battery_level > 40 %} yellow

                  {% elif battery_level > 30 %} amber

                  {% elif battery_level > 20 %} orange

                  {% elif battery_level > 10 %} deep-orange

                  {% else %} red

                  {% endif %}
                tap_action:
                  action: more-info
                entity: sensor.main_gym_battery
                layout: vertical
              - type: custom:mushroom-lock-card
                entity: lock.main_gym
                name: Main Gym Door
                primary_info: none
                secondary_info: none
                icon_type: none
            card_mod:
              style: |
                ha-card {
                  {% if is_state('lock.main_gym','locked') and
                  is_state('binary_sensor.main_gym_door', 'off') %}
                    background: rgba(145,2,2,0.5);
                  {% elif is_state('binary_sensor.main_gym_door', 'on') %}
                    background: rgba(130,130,0,0.5);
                  {% else %}
                    background: rgba(2,61,2,0.5);
                  {% endif %}
                }
          - type: custom:stack-in-card
            cards:
              - type: custom:mushroom-template-card
                primary: Main Front Door
                secondary: |-
                  {% if is_state('binary_sensor.main_front_door_door','on') %}
                    Door Open
                  {% elif is_state('lock.main_front_door','unlocked') %}
                    Unlocked
                  {% else %}
                    Locked
                  {% endif%}
                icon: |-
                  {% if is_state('binary_sensor.main_front_door_door','on') %}
                    mdi:door-open
                  {% elif is_state('lock.main_front_door','unlocked') %}
                    mdi:lock-open
                  {% else %}
                    mdi:lock
                  {% endif%}
                icon_color: >-
                  {% if is_state('lock.main_front_door','locked') and
                  is_state('binary_sensor.main_front_door_door','off') %}
                    red
                  {% elif is_state('binary_sensor.main_front_door_door','on') %}
                    yellow
                  {% else %}
                    green
                  {% endif%}
                badge_icon: >-
                  {% set battery_level =
                  (states('sensor.main_front_door_battery') | int / 10) |
                  round(0) | int * 10 %} {% if battery_level == 100 %}
                  mdi:battery {% elif battery_level > 0 %} mdi:battery-{{
                  battery_level }} {% else %} mdi:battery-alert-variant-outline
                  {% endif %}
                badge_color: >-
                  {% set battery_level =
                  states('sensor.main_front_door_battery') | int %}

                  {% if battery_level > 90 %} green

                  {% elif battery_level > 60 %} light-green

                  {% elif battery_level > 50 %} lime

                  {% elif battery_level > 40 %} yellow

                  {% elif battery_level > 30 %} amber

                  {% elif battery_level > 20 %} orange

                  {% elif battery_level > 10 %} deep-orange

                  {% else %} red

                  {% endif %}
                tap_action:
                  action: more-info
                entity: sensor.main_front_door_battery
                layout: vertical
              - type: custom:mushroom-lock-card
                entity: lock.main_front_door
                name: Main Front Door
                primary_info: none
                secondary_info: none
                icon_type: none
            card_mod:
              style: |
                ha-card {
                  {% if is_state('lock.main_front_door','locked') and
                  is_state('binary_sensor.main_front_door_door', 'off') %}
                    background: rgba(145,2,2,0.5);
                  {% elif is_state('binary_sensor.main_front_door_door', 'on') %}
                    background: rgba(130,130,0,0.5);
                  {% else %}
                    background: rgba(2,61,2,0.5);
                  {% endif %}
                }
          - type: custom:stack-in-card
            cards:
              - type: custom:mushroom-template-card
                primary: Main Hot Tub Door
                secondary: >-
                  {% if
                  is_state('binary_sensor.main_basement_to_hot_tub_door','on')
                  %}
                    Door Open
                  {% elif is_state('lock.main_basement_to_hot_tub','unlocked')
                  %}
                    Unlocked
                  {% else %}
                    Locked
                  {% endif%}
                icon: >-
                  {% if
                  is_state('binary_sensor.main_basement_to_hot_tub_door','on')
                  %}
                    mdi:door-open
                  {% elif is_state('lock.main_basement_to_hot_tub','unlocked')
                  %}
                    mdi:lock-open
                  {% else %}
                    mdi:lock
                  {% endif%}
                icon_color: >-
                  {% if is_state('lock.main_basement_to_hot_tub','locked') and
                  is_state('binary_sensor.main_basement_to_hot_tub_door','off')
                  %}
                    red
                  {% elif
                  is_state('binary_sensor.main_basement_to_hot_tub_door','on')
                  %}
                    yellow
                  {% else %}
                    green
                  {% endif%}
                badge_icon: >-
                  {% set battery_level =
                  (states('sensor.main_basement_to_hot_tub_battery') | int / 10)
                  | round(0) | int * 10 %} {% if battery_level == 100 %}
                  mdi:battery {% elif battery_level > 0 %} mdi:battery-{{
                  battery_level }} {% else %} mdi:battery-alert-variant-outline
                  {% endif %}
                badge_color: >-
                  {% set battery_level =
                  states('sensor.main_basement_to_hot_tub_battery') | int %}

                  {% if battery_level > 90 %} green

                  {% elif battery_level > 60 %} light-green

                  {% elif battery_level > 50 %} lime

                  {% elif battery_level > 40 %} yellow

                  {% elif battery_level > 30 %} amber

                  {% elif battery_level > 20 %} orange

                  {% elif battery_level > 10 %} deep-orange

                  {% else %} red

                  {% endif %}
                tap_action:
                  action: more-info
                entity: sensor.main_basement_to_hot_tub_battery
                layout: vertical
              - type: custom:mushroom-lock-card
                entity: lock.main_basement_to_hot_tub
                name: Main Hot Tub Door
                primary_info: none
                secondary_info: none
                icon_type: none
            card_mod:
              style: |
                ha-card {
                  {% if is_state('lock.main_basement_to_hot_tub','locked') and
                  is_state('binary_sensor.main_basement_to_hot_tub_door', 'off') %}
                    background: rgba(145,2,2,0.5);
                  {% elif is_state('binary_sensor.main_basement_to_hot_tub_door', 'on') %}
                    background: rgba(130,130,0,0.5);
                  {% else %}
                    background: rgba(2,61,2,0.5);
                  {% endif %}
                }
    card_mod:
      style: |
        ha-card {
          background-color: rgba(0,0,0,0.85);
        }

Multiple rows / colums can be done like:

grid-row-start: auto 
grid-row-end: span 2

grid-column-start: auto
grid-column-end: span 2

on the view options per grid item

I used a grid layout and was able to get what i was looking for.

Hello guys,

Do you know how to remove this difference from other cards using the grid layout-card?

image

margin: 0
grid-template-columns: 85% 1fr
grid-template-areas: |
  "left right"
mediaquery:
  "(max-width: 600px)":
    grid-template-columns: 80% 1fr
    grid-template-areas: |
      "left right"

Thank you a lot for your help :laughing:

Use the margin: setting like this margin: -10px 0px 0px 0px

margin: -10px 0px 0px 0px
grid-template-columns: 85% 1fr
grid-template-areas: |
  "left right"
mediaquery:
  "(max-width: 600px)":
    grid-template-columns: 80% 1fr
    grid-template-areas: |
      "left right"
1 Like

As an FYI to everyone using this: With the new 2024.06 update, layout-card dashboards break if they are using the break-card. The dashboard will all just be in one column instead of multiple.

Github issue is already present for this: Layout-break doesn't cause a column break in HA 2024.6 · Issue #291 · thomasloven/lovelace-layout-card · GitHub

I want to document the fix here. Editing the yaml configuration of the dashboard, changing this:

type: custom:vertical-layout

to this:

type: custom:layout-card
layout_type: custom:vertical-layout

The caveat with this fix is that the dashboard will no longer be editable in the GUI, just in YAML. But it should provide you with a quick fix until a fix is merged or you build an alternative dashboard (e.g. with vertical stacks).

3 Likes

I will wait for the Fix.
Or is there another card that does the same.

1 Like

I’m wondering the same. I have 5+ dashboards that uses the layout-card break and I’d hate to do this global config for each of them if a fix is right around the corner.

I don’t believe the Layout-card is being maintained any longer. 83 open issues at the moment and this fix has been waiting for three weeks.

So looks like I may have to indeed abandon layout-card. What alternatives have you guys been using? Specifically for adding breaks.

I’m looking as well. I strictly only use the grid-layout but haven’t found anything comparable.

Does anyone knows how to change this margin to 0px? I have tried many approaches using styles or card_mod but with no success:

add:

masonry-view-card-margin: "0"

to your theme yaml

I am sorry, first time doing this. Would it be in my card directly (if yes, how) or in my dashboard Raw configuration editor?

You’ll have to create a theme.yaml file to do this.

Install Studio Code Server on you HA instance (if not already present), open your config folder (this is where your configuration.yaml file is), create a new folder called “themes” and within that folder create a file yourthemename.yaml

in that file add the code mentioned by @sebbaT here. Then chose this as the theme for all the dashboards where this is relevant.

1 Like

max_columns: 3
image

I’m having problems making things go into columns. I have breaks in

image

everything is still in a single column

Stupid question from a pretty advanced Home Assistant user:

How do I install this via HACS? I don’t see it listed as Available.

I prefer to use HACS over the manual install to keep updates coming.

Thanks - Jonesie

My dashboard has been evolving, so I decided to standardize my layouts for each page, so I can manage the look and feel, but also make it responsive for my PC, phone and tablet.
I am using the layout card heavily.
My starting dashboard design for the learning curve is from [Madelena] with a few changes for what I want to do. (GitHub - Madelena/hass-config-public: My Dashboards for Home Assistant - Advanced data visualizations, responsive design, a neat maximalist Metro Live Tile layout, and an ultraminimal tablet layout!)

This is my main layout intent

#################################################
#            RESPONSIVE LAYOUT                  #
#################################################
#default
margin: 0
#grid-gap: var(--custom-layout-card-padding)
grid-gap: 5px
grid-template-columns: 25px minmax(20%, 1fr) repeat(3, 1fr) 25px
grid-template-rows: 75px repeat(3, fit-content(100%)) 55px
grid-template-areas: |
  ". sidebar header1 header2 header3 ."
  ". sidebar c c c ."
  ". sidebar c c c ."
  ". sidebar c c c ."
  ". sidebar footer1 footer2 footer3 ."
mediaquery:
  #phone
  "(max-width: 800px)":
    grid-gap: 5px
    grid-template-columns: auto
    grid-template-rows: auto auto auto repeat(5, auto)
    grid-template-areas: |
      "header1"
      "header2"
      "header3"
      "sidebar"
      "c"
      "footer1"
      "footer2"
      "footer3"
  #tablet
  "(max-width: 1200px)":
    grid-gap: 5px
    grid-template-columns: minmax(20%, 1fr) 1fr 0fr
    grid-template-rows: 75px 75px repeat(3, min-content) 55px auto
    grid-template-areas: |
      "header1 header1"
      "header2 header3 ."
      "sidebar c ."
      "sidebar c ."
      "sidebar c ."
      "sidebar c ."
      "sidebar footer1 ."
      "footer2 footer3 ."
  #tablet
  "(max-width: 1920px)":
    grid-gap: 5px
    grid-template-columns: minmax(20%, 1fr) repeat(3, 1fr) 0fr
    grid-template-rows: 75px repeat(3, fit-content(100%)) 55px
    grid-template-areas: |
      "sidebar header1 header2 header3 ."
      "sidebar c c c ."
      "sidebar c c c ."
      "sidebar c c c ."
      "sidebar footer1 footer2 footer3 ."

This works pretty well when I test with Chrome developers.

I have a question about area c.
I assumed that I can start placing cards in area c, and they will get placed one after the other in the 3 columns in c.
However, I get each card across the width of area c.

#Main Section of the dashboard page
  - type: "custom:layout-card"
    layout_type: "custom:grid-layout"
    view_layout:
      grid-area: c
      # place-self: center auto
    cards:
    # [Column] Current Conditions
    - type: custom:layout-card
      layout_type: custom:grid-layout
      layout: !include layouts/layout-live-tile.yaml
      cards:
        - type: 'custom:button-card'
          template: header_card
          variables:
            name: CURRENT CONDITIONS
            label: Accuweather
            arrow: 'mdi:arrow-top-right'
            action: url
            link: !secret accuweather_url
          view_layout:
            grid-column-start: 1
            grid-column-end: -1

        - type: 'custom:button-card'
          template:
            - live_tile
            - weather_precipitation
          variables:
            aspect_ratio: 2
          entity: sensor.pirateweather_precip_probability
          view_layout:
            grid-column: span 2

This is what I get:

I added a layout card in area c.
My first question is, do I need to do that or am I missing something that will force cards onto the columns in area c as defined.

layout:

grid-template-columns: 'repeat(auto-fill, [col-start] minmax(356px, 1fr) [col-end])'
grid-template-rows: auto
grid-column-gap: 32px
margin: -1px

code now is:

#Main Section of the dashboard page
  - type: "custom:layout-card"
    layout_type: "custom:grid-layout"
    view_layout:
      grid-area: c
      # place-self: center auto
    layout: !include layouts/layout-page-columns.yaml
    cards:
    # [Column] Current Conditions
    - type: custom:layout-card
      layout_type: custom:grid-layout
      layout: !include layouts/layout-live-tile.yaml
      view_layout:
        grid-column-start: 1
        grid-column-end: -3

had to read up on column-start and -end to make sure it is still responsive.
Now it looks like I want it to look like, but it is not responsive.


with smaller screen, you can see the overlaps.
image

Any idea what I need to change? This is the most customization I have ever done with grid and layout-cards.
I would like for the behavior to be the following:
As the screen get smaller, the area c content goes from 3 columns to 2, then to 1, so the total dashboard would be going from 4 (including sidebar) to 3 to 2, then ultimately to 1.
If the change is in the area c Layout-card, how do I account for the sidebar? given that mediaquery is on a screen size, not a child area size?

Apologize for the length of the post, trying to understand the structure so I can apply it across multiple areas I will be re-doing.