Custom Button Card Layout and Icons

I have been trying to mimic the attached design, but no matter what I do I can’t seem to get it right. This is what I got so far, but the layout is all over the place. How can I make this layout?

type: custom:button-card
entity: switch.basement_office_lights
name: Soffbord
label: Taklampa
icon: mdi:lightbulb-on-10
show_state: false
styles:
  card:
    - height: 80px
    - border-radius: 10px
    - padding: 0 10px
    - box-shadow: none
    - background-color: white
    - display: grid
    - grid-template-areas: '"icon info toggle"'
    - grid-template-columns: 50px 1fr 70px
    - align-items: center
  grid:
    - align-items: center
  icon:
    - color: teal
    - width: 36px
    - height: 36px
    - justify-self: center
  name:
    - font-size: 16px
    - font-weight: 500
    - color: black
  label:
    - font-size: 13px
    - color: gray
  custom_fields:
    toggle:
      - justify-self: center
custom_fields:
  toggle: >
    [[[ 
      const isOn = entity.state === 'on';
      const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
      return `
        <img src="${imageUrl}" style="
          height: 40px;
          width: 70px;
          object-fit: contain;
          transition: all 0.3s ease;">
      `;
    ]]]
tap_action:
  action: toggle

This is a rough version. There are a few ways to achieve this and others may have better methods.

It looks to me that this is stylized Tile or Mushroom card.

type: custom:button-card
entity: switch.basement_office_lights
name: Soffbord
label: Taklampa
icon: mdi:lightbulb-on-10
show_icon: true
show_state: true
styles:
  icon:
    - color: teal
    - width: 36px
    - height: 36px
    - justify-self: center
  grid:
    - position: relative
    - grid-template-areas: "\"i n s toggle\""
    - grid-template-columns: 25% 20% 30%
    - grid-template-rows: 1fr min-content min-content
  card:
    - background-color: white
    - height: 100px
  name:
    - font-size: 22px
    - font-weight: 200
    - color: black
  label:
    - font-size: 13px
    - color: black
  state:
    - margin-left: "-240px"
    - margin-bottom: "-40px"
    - font-weight: 200
    - color: grey
    - font-size: 20px
  custom_fields:
     toggle:
        - margin-bottom: "-20px"  
custom_fields:
  toggle: >
    [[[ 
      const isOn = entity.state === 'on';
      const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
      return `
        <img src="${imageUrl}" style="
          height: 40px;
          width: 70px;
          object-fit: contain;
          transition: all 0.3s ease;">
      `;
    ]]]
tap_action:
  action: toggle

This is exactly what I was looking for. Thank you!!!

On the web browser the card looks great. However, on the mobile app the name “Office Lights” gets cut off. I played around with grid-template-columns: 25% 20% 30%, but the name still cuts off.

What dashboard type do you have the card on?

I am using a grid layout.

I actually figured out the text alignment. I added justify-self: start to the name.

  name:
    - font-size: 20px
    - font-weight: 200
    - color: black
    - justify-self: start

What I can’t seem to figure it is how to make the grid’s background to match the card’s background and add the separation lines.

Can you post your updated card code?

I am using a vertical-stack here, but it works the same in a grid

type: vertical-stack
cards:
  - type: custom:button-card
    entity: switch.basement_office_lights
    name: Office Lights
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      label:
        - font-size: 13px
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle
  - type: custom:button-card
    entity: light.theater_lights
    name: Theater Lights
    label: Taklampa
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle

Is this what you are looking for?

type: 'custom:mod-card'
style: |
  ha-card {
    background-color: rgb(243,243,243);
  }
card:
  type: vertical-stack
  cards:
  - type: custom:button-card
    entity: switch.kitchen_lights
    name: Office Lights
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      label:
        - font-size: 13px
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle
  - type: entities
    entities:
      - type: divider
        style:
         background-color: lime
    card_mod:
     style: |
      ha-card {
        background-color: rgb(243,243,243);}
  - type: custom:button-card
    entity: light.bathroom_lights
    name: Theater Lights
    label: Taklampa
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle

I am getting this error on my end. Is it related to card-mod? If so, I have it installed and working.

ButtonCardJSTemplateError: TypeError: Cannot read properties of undefined (reading ‘state’) in ‘const isOn = entity.state === ‘on’; const imageUrl = isOn ? ‘/local/custom_icons/toggle_on.png’ …’

use your entity. I posted the code with mine.
image

LoL! Duh! Thanks!

The layout is still off. I used a manual card.
Screenshot 2025-01-20 214700

You have this at the top of the card?

type: custom:mod-card
style: |
  ha-card {
    background-color: rgb(243,243,243);
  }
card:

Yes. I copied your code and updated the entities with my own.

type: 'custom:mod-card'
style: |
  ha-card {
    background-color: rgb(243,243,243);
  }
card:
  type: vertical-stack
  cards:
  - type: custom:button-card
    entity: switch.basement_office_lights
    name: Office Lights
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      label:
        - font-size: 13px
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle
  - type: entities
    entities:
      - type: divider
        style:
         background-color: lime
    card_mod:
     style: |
      ha-card {
        background-color: rgb(243,243,243);
  - type: custom:button-card
    entity: light.theater_lights
    name: Theater Lights
    label: Taklampa
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle

Would you be willing to use custom: stack-in-card? It’s a lot easier to modify vs the standard vertical-stack card

type: custom:stack-in-card
cards:
  - type: custom:button-card
    entity: switch.basement_office_lights
    name: Office Lights
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      label:
        - font-size: 13px
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle
  - type: entities
    entities:
      - type: divider
        style:
          background-color: lime
    card_mod:
      style: |
        ha-card {
          background-color: rgb(243,243,243);
          border-style: none;
          }
  - type: custom:button-card
    entity: light.bathroom_lights
    name: Theater Lights
    label: Taklampa
    icon: mdi:lightbulb-on-10
    show_icon: true
    show_state: false
    styles:
      icon:
        - color: rgb(84,115,144)
        - width: 36px
        - height: 36px
        - justify-self: center
      grid:
        - position: relative
        - grid-template-areas: "\"i n s toggle\""
        - grid-template-columns: 18% 40% 22%
        - grid-template-rows: 1fr min-content min-content
      card:
        - background-color: rgb(243,243,243)
        - height: 70px
        - border: 0px
      name:
        - font-size: 20px
        - font-weight: 200
        - color: black
        - justify-self: start
      state:
        - margin-left: "-240px"
        - margin-bottom: "-40px"
        - font-weight: 200
        - color: grey
        - font-size: 12px
      custom_fields:
        toggle:
          - margin-bottom: "-10px"
    custom_fields:
      toggle: |
        [[[ 
          const isOn = entity.state === 'on';
          const imageUrl = isOn ? '/local/custom_icons/toggle_on.png' : '/local/custom_icons/toggle_off.png';
          return `
            <img src="${imageUrl}" style="
              height: 30px;
              width: 70px;
              object-fit: contain;
              transition: all 0.3s ease;">
          `;
        ]]]
    tap_action:
      action: toggle
card_mod:
  style: |
    ha-card {
      background-color: rgb(243,243,243);
      border-style: none;
      }
1 Like

I don’t mind using custom: stack-in-card. Never used it before though.

Are you on the latest card-mod?

image

I am on 3.5.0
Screenshot 2025-01-20 220252

They pulled that version

This is most likely why we are getting different results.

I just downgraded to 3.4.4.

I am assuming I have to install the stack-in-card using HACS?

Yes, it’s a great card to have when customizing cards. custom:layout-card is another.