Mushroom Cards - Build a beautiful dashboard easily šŸ„ (Part 2)

Here is an example after consolidating your code…

type: custom:mushroom-template-card
primary: Primary Text
secondary: Secondary Text
icon: mdi:mushroom
entity: light.bathroom_lights
card_mod:
      style:  
        mushroom-shape-icon$: |
                .shape {
                  --shape-color: blue !important; 
                  --icon-symbol-size: 50px;
                  --icon-size: 70px;
                } 
        .: |        
         ha-state-icon {
                color: {{ 'orange' if is_state(config.entity, 'on') else 'white' }};
                }
         ha-card {
                padding: 10px 0px 10px 0px !important; 
                                  }
2 Likes

Excellent - not only very efficient,but also working :slight_smile:
Thanks a lot!

Why is here no animation?

type: custom:mushroom-template-card
icon: mdi:shower-head
icon_color: light-blue
primary: Shower
card_mod:
  style:
    mushroom-shape-icon$: |
      ha-icon {
        --icon-animation: clip 0.7s ease-out infinite;
      }
      @keyframes clip {
        0% {clip-path: inset(0 0 45% 0); }
        100% { clip-path: inset(0 0 0 0); }

You are using outdated code… Try this:

type: custom:mushroom-template-card
icon: mdi:shower-head
icon_color: light-blue
primary: Shower
card_mod:
  style: |
     ha-state-icon {
        animation: clip 0.7s ease-out infinite;
        }
      @keyframes clip {
        0% {clip-path: inset(0 0 45% 0); }
        100% { clip-path: inset(0 0 0 0); }

1 Like

Thanks, that is the solution :raised_hands:

Try this

type: custom:mod-card
card:
 type: custom:mushroom-template-badge
 content: ""
 icon: mdi:shield-alert-outline
 color: >-
  {% if is_state("alarm_control_panel.omnilink_main", "armed_away") or
  is_state("alarm_control_panel.omnilink_main", "arming") %} Red {% else %} Grey
  {% endif %}
 tap_action:
  action: perform-action
  perform_action: alarm_control_panel.alarm_arm_away
  target:
    entity_id: alarm_control_panel.omnilink_main
  data: {}
card_mod:
  style:
    mushroom-template-badge$: |
     ha-state-icon {
        animation: blink 1s linear infinite;
     }
      @keyframes blink {
       50% {opacity: 0;}
     }
1 Like

How can i use the default icon from the integration/entity in a mushroom-template-card?
I just want to change the color depending on state, icon needs to stay standard as it is provided by the entity/integration.

If i don’t specify the icon, none is shown.

I know this way is possible.

type: custom:mushroom-template-card
primary: Hello, {{user}}
secondary: How are you?
picture: "{{ state_attr('sensor.steam', 'entity_picture') }}"
		
 

Thx for the tip, stupid i didn’t think of that!

I fixed it with:

icon: "{{ state_attr('sensor.mysensor', 'icon') }}"
1 Like

Hi,
Can someone help me?
Is it possible to remove the borders and background of the custom:mushroom-template-badge card?

image

type: custom:mod-card
card:
  type: custom:mushroom-template-badge
  icon: |
    {% if states('sensor.atualizacoes_disponiveis_quantidade') | int > 0 %}
      mdi:update
    {% else %}
      mdi:check-circle
    {% endif %}
  content: "{{ states('sensor.atualizacoes_disponiveis_quantidade') }}"
  label: AtualizaƧƵes
  color: |
    {% if states('sensor.atualizacoes_disponiveis_quantidade') | int > 0 %}
      blue
    {% else %}
      green
    {% endif %}
  tap_action:
    action: navigate
    navigation_path: /lovelace/monitoramento
card_mod:
  style:
    mushroom-template-badge$: |
      {% if states('sensor.atualizacoes_disponiveis_quantidade') | int > 0 %}
      ha-state-icon {
        animation: blink 1s linear infinite;
      }
      @keyframes blink {
        50% { opacity: 0; }
      }
      {% endif %}

I haven’t been able to figure it out :frowning:

Try this out

card_mod:
  style:
    mushroom-template-badge$: |
      ha-state-icon {
       animation: {{ 'blink 1s linear infinite' if states('sensor.atualizacoes_disponiveis_quantidade') | int(0) > 0  else 'none' }};
        }
      .badge{
       border: none !important;
        }
      @keyframes blink {
        50% { opacity: 0; }
       }
2 Likes

I like, thanks very much :clap::clap::clap:

I’m using the mushroom template card and as entity I used a picture entity.
As picture I use this;
{{ state_attr(entity, ā€˜entity_picture’) }}

This is working, but the picture is small, is there a way to zoom this in?
Have searched for it but can not find it.

anyone made a weather-card or dashboard yet?

Hi @LiQuid_cOOled

I need to know if you can help me please
I’m trying to use the same logic in another card, but I didn’t succeed :frowning:

I’m trying to change the color of the text in the ā€œcontentā€ and also remove the borders.
image

The card consists of using auto-entities to search in a json received via MQTT from clients connected to my VPN. But for this test, I put the name of the mocked client as an example.

type: custom:auto-entities
card:
  type: horizontal-stack
card_param: cards
show_empty: false
filter:
  template: >
        ## {% set ns = namespace(cards=[]) %}
        ## {% set data = state_attr('sensor.clientes_vpn_dinamicos', 'clientes') %}
        ## {% set clients = from_json(data) if data is string else data %}

       ## {% for client in clients %}
          ## {% if client.status == 'online' %}
           ## {% set ns.cards = ns.cards + [{

    {% set hostname = 'thiago-iphone' %}
    [
      {
        "type": "custom:mushroom-template-badge",
        "label": "Conectado na VPN",
        "content": "{{ hostname }}",
        "card_mod": {
          "style": {
            "$": {
              ".badge": {
                "border": "none !important"
              },
              ".content": {
                "color": "green !important"
              }
            }
          }
        }
      }
    ]

To mod the Mushroom Badge Card, it has to be nested within a type: custom:mod-card

I have never used card mod on a 2nd nested card with a auto-entities card. If you want to go that route post your inquiry here

The auto entities card provides a ton of filter options so I am not sure a templated filter is required when using an imbedded custom card. I think adding a mushroom template badge card also adds more complexity than necessary.

For example… you can use the Mushroom Entity Card and match the look of the template badge.

image

type: custom:auto-entities
card:
  type: horizontal-stack
card_param: cards
show_empty: false
filter:
  include:
    - domain: light
      attributes:
        brightness: ">= 250"
      options:
        type: custom:mushroom-entity-card
        icon_type: none
        secondary_info: name
        primary_info: none
        card_mod:
          style:
            mushroom-state-info$: |
              .primary:after {
                  content: "Conectado na VPN";
                  color: #b3b3b3 !important;
                  font-weight: 400;
                  font-size: 12px !important;
                 }
              .secondary {
                  color: lime !important;
                  opacity: 70%;
                  font-size: 11px !important;
                  margin-top: -4px;
                }
            .: |
              ha-card {
               border: none;
               border-radius: 30px 30px;
               text-align: center;
               height:  36px !important;
               }

You can use any of the following to isolate the devices you want to display when they are connected

Filters

The two main filter sections include and exclude each takes a list of filters.

Each filter has a set of rules and will match entities which match ALL rules:

Rule Matches Example
domain Entity domain light, binary_sensor, media_player
state Current state of entity. "on", home, "3.14", "Triggered"
entity_id Full entity id light.bed_light, input_binary.weekdays_only
name Friendly name attribute Kitchen lights, Front door
group Entities in the group group.living_room_lights
area Entities in a given area. Also matches all entities belonging to a Device in the area. Kitchen
floor Entities on a given floor. Also matches all entities belonging to a Device on that floor. Second, Basement
level Entities on a given level. 2, >1
device Entities belonging to a Device Thomas iPhone
label Entities that are tagged with a certain label Show on dashboard, Holiday light
device_manufacturer Entities belonging to a device by a given manufacturer IKEA
device_model Entities belonging to a device of a given model Hue white ambiance E26/E27 (8718696548738)
integration Entities included by a given integration. This is not possible for all integrations. plex, input_boolean, xiaomi_miio, mobile_app
hidden_by Who has hidden an entity user, integration
attributes Map of attribute: value pairs to match
last_changed Time since last state change (defaults to minutes) < 15, > 2 d ago
last_updated Time since last update (defaults to minutes) < 15, > 2 d ago
entity_category Entity category config, diagnostic
3 Likes

thanks for the feedback, I will follow this suggestion

1 Like

Keep me updated

1 Like

Thanks to your feedback, I was able to achieve the result.

image

type: custom:auto-entities
card:
  type: horizontal-stack
card_param: cards
show_empty: false
filter:
  template: >
    {% set clientes = state_attr('sensor.clientes_vpn_dinamicos', 'clientes') |
    default([]) %} {% set ns = namespace(cards=[]) %} {% for c in clientes if
    c.status == 'online' %}
      {% set card = {
        "type": "custom:mushroom-entity-card",
        "entity": "sensor.clientes_vpn_dinamicos",
        "name": c.hostname,
        "icon_type": "icon",
        "icon": "mdi:vpn",
        "primary_info": "none",
        "secondary_info": "name",
        "card_mod": {
          "style": {
            "mushroom-state-info$": "
              .primary:after {
                content: 'Online VPN';
                color: #b3b3b3 !important;
                font-weight: 400;
                font-size: 12px !important;
              }
              .secondary {
                color: green !important;
                font-size: 11px !important;
                margin-top: -4px;
                font-weight: bold !important;
                
              }
            ",
            ".": "
              ha-card {
                border: none;
                text-align: center;
                height: 36px !important;
                background: none !important;
              }
              mushroom-shape-icon {
                --icon-size: 30px;
                --icon-color: limegreen !important;
                --shape-color: transparent !important;
              }
            "
          }
        }
      } %}
      {% set ns.cards = ns.cards + [card] %}
    {% endfor %} {{ ns.cards }}


Hi guys a made a weather card with the custom animations from @dimitri.landerloos Mushroom Cards - Build a beautiful dashboard easily šŸ„ (Part 1) - #7717 by dimitri.landerloos

With his help and a few tweaks it’s here let me know what you guys think of it.
The card uses card mod and Muschroom cards. And on top of that it is build for the Openweathermap service and the Sun service. But feel free to make it suit your own wheater provider.

Schermafbeelding 2025-07-06 120905

It has support for the following wheater conditions:

  • clear-night
  • cloudy
  • exceptional
  • fog
  • hail
  • lightning
  • lightning-rainy
  • partlycloudy (daytime and nighttime with diffrent animations)
  • pouring
  • rainy
  • snowy
  • snowy-rainy
  • sunny
  • windy
  • windy-variant (wind with clouds)
type: custom:mushroom-template-card
primary: '{{ states(''sensor.openweathermap_condition'') | title }}'
icon: >-
  {% set icons = {
	'clear-night': 'mdi:weather-night',
	'cloudy': 'mdi:weather-cloudy',
	'exceptional': 'mdi:weather-cloudy-alert',
	'fog': 'mdi:weather-fog',
	'hail': 'mdi:weather-hail',
	'lightning': 'mdi:weather-lightning',
	'lightning-rainy': 'mdi:weather-lightning-rainy',
	'partlycloudy': 'mdi:weather-partly-cloudy' if is_state('sun.sun', 'above_horizon') else 'mdi:weather-night-partly-cloudy',
	'pouring': 'mdi:weather-pouring',
	'rainy': 'mdi:weather-rainy',
	'snowy': 'mdi:weather-snowy',
	'snowy-rainy': 'mdi:weather-snowy-rainy',
	'sunny': 'mdi:weather-sunny',
	'windy': 'mdi:weather-windy',
	'windy-variant': 'mdi:weather-windy-variant'
  } %}

  {{ icons.get(states('sensor.openweathermap_condition'),
  'mdi:help-circle') }}
icon_color: >-
  {% set colors = {
	'clear-night': 'amber',
	'cloudy': 'grey',
	'exceptional': 'red',
	'fog': 'grey',
	'hail': 'grey',
	'lightning': 'dark-grey',
	'lightning-rainy': 'dark-grey',
	'partlycloudy': 'orange',
	'pouring': 'blue',
	'rainy': 'light-blue',
	'snowy': 'grey',
	'snowy-rainy': 'grey',
	'sunny': 'amber',
	'windy': 'light-blue',
	'windy-variant': 'cyan'
  } %}

  {{ colors.get(states('sensor.openweathermap_condition'), 'white')
  }}
secondary: >-
  {{ (states('sensor.openweathermap_temperature') | float) |
  round(1, default=0) | string | replace('.', ',') }} °C feels like
  {{ (states('sensor.openweathermap_feels_like_temperature') |
  float) | round(1, default=0) | string | replace('.', ',') }} °C
grid_options:
  columns: 12
  rows: 1
tap_action:
  action: more-info
entity: sensor.openweathermap_temperature
card_mod:
  style: |
	ha-state-icon {
	  {% set condition = states('sensor.openweathermap_condition') %}
		{% if condition == 'clear-night' %} 
		  animation: moon 10s linear infinite, stars 5s linear infinite;
		{% elif condition == 'cloudy' %} 
		  animation: cloudy 10s ease-in-out infinite;
		{% elif condition == 'exceptional' %} 
		  animation: exceptional 400ms ease-in-out infinite;
		{% elif condition == 'fog' %} 
		  animation: cloudy 10s ease-in-out infinite, fog 4s infinite;
		{% elif condition == 'hail' %} 
		  animation: cloudy 10s ease-in-out infinite, hail 2s infinite; 
		{% elif condition == 'lightning' %}
		  animation: cloudy 10s ease-in-out infinite, lightning 4s infinite;
		{% elif condition == 'lightning-rainy' %}
		  animation: cloudy 10s ease-in-out infinite, lightning-rainy 4s infinite; 
		{% elif condition == 'partlycloudy' %}
		  {% if is_state('sun.sun', 'above_horizon') %}
			animation: cloudy 10s ease-in-out infinite, sun-partly 2s infinite;
		  {% else %}
			position: relative;
			z-index: 1;
			animation: cloudy 10s ease-in-out infinite;
			/* animation: cloudy 10s ease-in-out infinite, moon-partly 10s linear infinite; */
		  {% endif %}
		{% elif condition == 'pouring' %}
		  animation: cloudy 10s ease-in-out infinite, pouring 1s infinite;
		{% elif condition == 'rainy' %}
		  animation: cloudy 10s ease-in-out infinite, rainy 1.5s infinite; 
		{% elif condition == 'snowy' %}
		  animation: cloudy 10s ease-in-out infinite, snowy 4s infinite;
		{% elif condition == 'snowy-rainy' %}
		  animation: cloudy 10s ease-in-out infinite, snowy-rainy 4s infinite;
		{% elif condition == 'sunny' %}
		  animation: sunny 8s ease-in-out infinite alternate;
		{% elif condition == 'windy' %}
		  animation: windy 10s ease-in-out infinite; 
		  transform-origin: 15% 50%
		{% elif condition == 'windy-variant' %}
		  animation: cloudy 10s ease-in-out infinite, windy-variant 5s infinite;
		{% endif %}
	}
	ha-state-icon::after {
	  content: "";
	  position: absolute;
	  inset: 0;
	  background-color: rgba(73,52,22,1);
	  clip-path: polygon(0 58%, 27% 58%, 34% 47%, 44% 42%, 55% 42%, 69% 47%, 74% 64%, 100% 67%, 100% 0, 0 0);
	  opacity: 0;
	  {% set condition = states('sensor.openweathermap_condition') %}
		{% if condition == 'partlycloudy' %}
		  {% if is_state('sun.sun', 'below_horizon') %}
			animation: moon-partly 5s ease-in-out infinite alternate 1s; /* vertraagde fade-in */
		  {% endif %}
		{% endif %}
	  z-index: 2;
	  pointer-events: none;
	}
	@keyframes moon {
	  0%, 100% { transform: rotate(12deg); }
	  30% { transform: rotate(-6deg); }
	  45% { transform: rotate(8deg); }
	  75% { transform: rotate(-10deg); }
	}
	@keyframes moon-partly {
	  to {
		opacity: 1;
	  }
	}
	@keyframes stars {
	  0%, 3.1%, 14.1% { clip-path: inset(0 0 0 0); }
	  3% { clip-path: polygon(1% 1%, 0% 99%, 99% 100%, 99% 62%, 68% 62%, 62% 44%, 76% 34%, 100% 34%, 99% 0%); }
	  14% { clip-path: polygon(1% 1%, 0% 99%, 99% 100%, 100% 25%, 51% 45%, 38%, 34%, 36% 0); }
	}
	@keyframes cloudy {
	  0%, 100% { transform: translateX(3px); }
	  30% { transform: translateX(-1px); }
	  45% { transform: translateX(1.5px); }
	  75% { transform: translateX(-3.2px); }
	}
	@keyframes exceptional {
	  0%, 100% { transform: translate(0, 0)}
	  20%  { transform: translate(0px, -0.3px)}
	  40%  { transform: translate(0px, 0.3px)}
	  60%  { transform: translate(0px, 0.3px)}
	  80%  { transform: translate(0px, -0.3px)}
	}
	@keyframes fog {
	  0%, 26%, 76%, 100% { clip-path: inset(0 0 0 0); }
	  25% { clip-path: polygon(0 0, 100% 0, 100% 59%, 60% 59%, 60% 74%, 100% 74%,100% 100%, 0 100%); }
	  75%  { clip-path: polygon(0 0, 100% 0, 100% 100%, 26% 100%, 26% 76%, 0 76%);}
	}
	@keyframes hail {
	  0%, 26%, 51%, 76%, 100% { clip-path: inset(0 0 0 0); }
	  25% { clip-path: polygon(0 0, 100% 0, 100% 100%, 62% 100%, 47% 69%, 56% 55%, 43% 43%, 31% 58%, 48% 68%, 63% 100%, 0 100%); }
	  50%  { clip-path: polygon(0 0, 100% 0, 100% 100%, 62% 100%, 61% 86%, 74% 74%, 61% 60%, 46% 69%, 60% 87%, 63% 100%, 0 100%); }
	  75%  { clip-path: polygon(0 0, 100% 0, 100% 100%, 47% 100%, 56% 83%, 42% 68%, 27% 81%, 37% 100%, 0 100%); }
	}
	@keyframes lightning {
	  0%, 10%, 12.1%, 15%, 18.1%, 20%, 100% { color: rgb(var(--rgb-dark-grey)); clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 72% 71%, 61% 34%, 41% 35%, 29% 87%, 0% 100%);}
	  10.1%, 12%, 15.1%, 18% { color: rgb(var(--rgb-white)); clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%); }
	}
	@keyframes lightning-rainy {
	  0%, 10%, 12.1%, 15%, 18.1%, 20%, 49.9% { color: rgb(var(--rgb-dark-grey)); clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 73% 62%, 77% 54%, 60% 36%, 38% 36%, 20% 51%, 23% 63%, 0% 100%);}
	  10.1%, 12%, 15.1%, 18% { color: rgb(var(--rgb-white)); clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 73% 62%, 77% 54%, 60% 36%, 38% 36%, 61% 44%, 47% 100%, 0% 100%); } 
	  50%, 100%{ color: rgb(var(--rgb-dark-grey)); clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 40% 99%, 58% 47%, 60% 36%, 38% 36%, 20% 51%, 23% 63%, 0% 100%); }
	}
	@keyframes sun-partly {
	  50% { clip-path: polygon(0 67%, 18% 55%, 16% 31%, 41% 12%, 67% 24%, 77% 59%, 100% 64%, 100% 100%, 0 100%); }
	}
	@keyframes pouring {
	  0%, 50%, 100% { clip-path: inset(0 0 0 0); }
	  25% { clip-path: polygon(0 0, 100% 0, 100% 83%, 54% 83%, 62% 47%, 47% 46%, 38% 83%, 0 83%); }
	  75%  { clip-path: polygon(0 0, 100% 0, 100% 70%, 75% 70%, 80% 48%, 63% 48%,
	  54% 94%, 32% 94%, 46% 46%, 30% 46%, 23% 72%, 0 72%); }
	}
	@keyframes rainy {
	  50% { clip-path: polygon(0 0, 100% 0, 100% 73%, 71% 73%, 50% 39%, 29% 73%, 0 73%); }
	}
	@keyframes snowy {
	  50% { clip-path: polygon(0 0, 100% 0, 100% 100%, 65% 100%, 76% 73%, 57% 49%, 34% 56%, 26% 79%, 37% 100%, 0 100%); }
	  51% { clip-path: inset(0 0 0 0); }
	}
	@keyframes snowy-rainy {
	  0%, 32%, 100% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 79% 100%, 77% 71%, 70% 44%, 26% 43%, 13% 67%, 14% 100%, 0% 100%); }
	  33%, 65.9% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 59% 100%, 56% 75%, 70% 44%, 26% 43%, 13% 67%, 14% 100%, 0% 100%); }
	  66%, 99.9% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 79% 100%, 77% 71%, 70% 44%, 45% 39%, 62% 59%, 51% 100%, 0% 100%); }
	}
	@keyframes sunny {
	  70% { transform: rotate(360deg) scale(1); }
	  80% { transform: scale(1); }
	  90% { transform: scale(1.15); }
	  100% { transform: scale(1); }
	}
	@keyframes windy {
	  0%, 100% { transform: scaleX(1.2); }
	  30% { transform: scaleX(0.9); }
	  45% { transform: scaleX(1.1); }
	  75% { transform: scaleX(0.8); }
	}
	@keyframes windy-variant {
	  0%, 50%, 100% { clip-path: inset(0 0 0 0); }
	  25% { clip-path: inset(0 0 37% 0); }
	}
6 Likes