⚪ Bubble Card - A minimalist card collection for Home Assistant with a nice pop-up touch

just tested on H.A last version aug 2024.
I’ve some 'bubble whil in the setting but as soon as the dashboard is saved the vertical stack ou the bubble card are not present.

this is the code of it:


type: vertical-stack
cards:
  - type: custom:bubble-card
    card_type: pop-up
    button_type: state
    entity: sensor.thermometre_salon_temperature
    icon: mdi:temperature-celsius
    hash: '#pop-up-name#temp-salon'
    show_header: true
    name: Temp. Salon
title: bubble

Thank you

Hi everyone,

discovered this amazing card and figured it’s time to polish my dashboards.

Generally it is working as described, just 1 thing drives me crazy.

I’d like to replace the lower section part (Klima and the 2 following card) with a popup-card.
I added my standard style settings to the card

The card with the rounded border is the popup-button-card, with the following code:

type: custom:bubble-card
card_type: button
button_type: name
name: Klima
icon: mdi:temperature-celsius
button_action:
  tap_action:
    action: navigate
    navigation_path: '#showtime'
card_layout: large
card_mod:
  style: |
    ha-tile-icon {
      --mdc-icon-size: 30px;
    }
    ha-icon-button {
      width: 90px !important;
      height: 90px !important;
    }
    ha-card {
      --ha-card-background: #;
      font-size: 40px;
      border-radius: 15px;
      box-shadow: rgba(195, 255, 104, 1) 0px 1px 50px;
    }
    ha-card {
    --primary-text-color: grey;
    }

As you can see it accepts some card-mod styles (border-radius & primary-text-color), and ignores others (box-shadow)

I moved the card to the end, to show the box-shadow in the 1st picture is actually those
of the adjactend cards.

Can someone help me out with centering icon and text and add the box-shadow ?

For the sake of completeness, the actual popup with the working styles

1 Like

I would know if it’s possible to make a button like :

type: custom:bubble-card
card_type: button
card_layout: normal
button_type: name
show_icon: false
show_name: true
name: Aspirateur
sub_button:
  - entity: vacuum.dreame_robot_vacuum_d9
  - name: Clean mode
    show_background: false
    entity: select.dreame_robot_vacuum_d9_cleaning_mode
    show_state: false
    show_attribute: true
    show_last_changed: false
    show_arrow: true
    show_name: true
  - name: Suction Level
    entity: select.dreame_robot_vacuum_d9_suction_level
    show_state: false
    show_attribute: true
    show_last_changed: false
    show_arrow: true
    show_name: true

But for the climate enity of versatile thermostat.
And show current temp, temperature, security_state attributes like state. And in sub-button : preset_mode selection ?

Thanks.

Hi all,

is it possible to set the visibility of “show_last_changed” dynamically depending on a button state (on / off) , like in the styles section?

I would like to use it for a sleep timer (starting when pressing the button and showing with show_last_changed when the sleep timer was started. But if the sleep timer is off, i would like to hide show_last_changed, because it’s not necessary and rather confusing.

I’ve tried something like this:

show_last_changed: >-
[[[ is_state(‘input_boolean.onoffsleeptimertv’, ‘on’) | iif(‘true’, ‘false’)
]]]

and various other ways ( with {}, as $hass.state), but i can’t get it working.

Is there a way to do it?

Regards, Rudi

image
Anyone know how to change the width of the select list? The list items are being clipped.

Its really good documentated in the github:

U need an extra button to call the popup you created.
Something like:

type: custom:bubble-card
card_type: button
entity: switch.pi_hole
show_attribute: false
sub_button:
  - entity: sensor.pi_hole_werbungsanteil_heute_blockiert
    show_state: true
    show_icon: true
    show_last_changed: false
    show_attribute: false
    attribute: friendly_name
    show_background: false
    icon: mdi:lock-percent
    name: ''
  - entity: sensor.pi_hole_werbung_heute_blockiert
    show_state: true
    show_icon: true
    show_background: false
    icon: mdi:advertisements
card_layout: large-2-rows
button_action:
  double_tap_action:
    action: none
    navigation_path: '#pihole'
  hold_action:
    action: navigate
    navigation_path: '#pihole'
tap_action:
  action: toggle
columns: 2
show_name: false
scrolling_effect: true
show_icon: true
force_icon: false
show_state: false
show_last_changed: false
double_tap_action:
  action: none
  navigation_path: '#pihole'
hold_action:
  action: navigate
  navigation_path: '#pihole'

Here im calling my “#pihole”-popup if im ether double-click or hold the button.

1 Like

Love these cards. I want the icon for one of my bubble cards to be a web URL image. I can’t find a way to do that.

The scenario is I am using the PS5 integration and I get the game that is being played as an attribute of a sensor. I’d love to have a bubble card that shows whats playing (the icon), along with the title of the game (text) and then the power on/off button.

I can do it all but the image of the game as the icon.

Has anyone successfully made a Bubble Card for RGB color strips? Want to be able to slide for color temp, as well as select modes like “sunset, audio sync” etc.

Hi everyone,
Yesterday, I built a completely new smartphone dashboard.
After archiving the custom-room card on GitHub, I’m now looking for a variant of a person card. I’m not satisfied with the current person card, so I’m searching for something new.

1 Like

Thats exactly i want to achive.

Could I see your yaml for the bubble card? :slight_smile:

Very nice, how were you able to keep the margins limited?
When I try to achieve the same there it is too much white space to my liking.

Hi, I’ve been redoing my HA setup for the last month after years of neglect. For the last week I’ve been working on the interface. My primary view had been a massive series of multiple-entity-row. I’ve been making a series of mostly state bubble cards in an effort to somewhat keep the mechanics the same. I’ve run into something a bit odd. Hopefully, with a couple of screenshots and a snippet of yaml, the problem will become evident.

So at the bottom of the screenshot in the card called “finished basement”, the focus here will be on the two left most sub buttons. The bottom one is orange background. Not in the screen shot is a similar containing multiple-entity-row with the same icons. The tap action is toggle. When I have the following code in the state card:

styles: >-
  ha-card {

  ${subButtonIcon[3].setAttribute("icon",
  hass.states['sensor.watts_treadmill'].state > 5 ? 'mdi:run-fast' : 'mdi:run')}
  ${subButtonIcon[4].setAttribute("icon",
  hass.states['sensor.foodlevel_petsafe'].state === 'full' ? 'mdi:cat' :
  'mdi:cat')}

  }

  .bubble-icon {
    color: ${state === 'on' ? '#FFE500' : ' '} !important;
  }

  .bubble-sub-button-1 {
    color: ${hass.states['light.basementstairs'].state = 'on' ? 'yellow' : ' '
  }

  .bubble-sub-button-2 {
    color: ${hass.states['switch.basementstairs'].state = 'on' ? 'yellow' : ' '
  }

  .bubble-sub-button-4 {
    background-color: ${hass.states['sensor.watts_treadmill'].state > 5 ? 'goldenrod' : ' ' }
    color: ${hass.states['sensor.watts_treadmill'].state > 5 ? 'grey' : ' ' }
  }

  .bubble-range-fill {
    background: linear-gradient(to right, #FFFFFF, #FFE500) !important;
  }

the two sub buttons I mentioned earlier lose their tap action, the two corresponding buttons in my old interface lose their tap action, and when I go to the parent device for each of those lights, this is what I see:

Now going into either the switch or the light entities and toggling will get rid of the “yellow” and bring back the normal controls. However, the moment I go back to the view where the state bubble card is, they’re back to yellow again. Without even touching them.

I spent a couple of days reading the majority of this nearly 1500 posts strong thread. I honestly don’t recall seeing anything about something like this, but I’m sorry if this is something that was addressed already. Lastly, when I remove the yaml I pasted above, everything seems to go back to nornal.

I added a justify flex-end to the style of the bubble-sub-button-container with a gap of 20px, which controls the spacing between the buttons.

styles: >
           .bubble-button-card-container {
              background: none;
            }
          .bubble-sub-button {
            height: 50px !important;
            width: 60px !important;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
          }


          .bubble-sub-button-icon {
            --mdc-icon-size: 20px !important;
            margin-bottom: 4px; /* Abstände zwischen Icon und Name */
          }


          .bubble-name-container {
            margin-right: 0px !important;
            text-align: center;
          }


          .bubble-sub-button-container {
            width: 100%;
            justify-content: flex-end; /* Rechtsbündige Ausrichtung der Buttons */
            gap: 20px; /* Kleiner Abstand zwischen den Buttons */}
          }

Okay with a lot of reading and by try and error I was able to align the text and the icon (another button)

type: custom:bubble-card
card_type: button
button_type: name
name: Wetter
icon: mdi:weather-partly-cloudy
button_action:
  tap_action:
    action: navigate
    navigation_path: '#wetter'
card_layout: large
layout-options:
  grid_rows: 1
  grid_columns: 2
layout_options:
  grid_columns: full
styles: |2-
      ha-card {
          margin-top: 0;
          background: none;
          opacity: 1;
      }
      .is-unavailable {
          opacity: 0.5;
      }

      .bubble-button-card-container {
          position: relative;
          width: 100%;
          height: 50px;
          background-color: var(--background-color-2,var(--secondary-background-color));
          border-radius: 32px;
          overflow: scroll;
          touch-action: pan-y;
      }

      .bubble-button-card,
      .bubble-range-slider,
      .bubble-button-background {
          display: flex;
          position: absolute;
          justify-content: space-between;
          align-items: center;
          height: 100%;
          width: 100%;
          transition: background-color 1.5s;
      }
      .bubble-button-background {
          background-color: var(--bubble-button-background-color);
          opacity: .5;
          border-radius: 32px;
      }
      .bubble-range-fill {
          position: absolute;
          top: 0;
          bottom: 0;
          left: 0;
          width: 100%;
          left: -100%;
          transition: all .3s;
      }
      .is-dragging .bubble-range-fill {
          transition: none;
      }
      .is-light .bubble-range-fill {
          opacity: 0.5;
      }
      .is-unavailable .bubble-button-card,
      .is-unavailable .bubble-range-slider {
          cursor: not-allowed;
      }
      .bubble-range-slider {
          cursor: ew-resize;
          border-radius: 25px;
          overflow: hidden;
      }
      .bubble-icon-container {
          display: flex;
          flex-wrap: wrap;
          align-content: center;
          justify-content: center;
          min-width: 38px;
          min-height: 38px;
          margin: 15px;
          border-radius: 50%;
          background-color: var(--card-background-color, var(--ha-card-background));
          overflow: hidden;
          position: relative;
          cursor: pointer;
      }
      .bubble-icon-container::after {
          content: '';
          background-color: currentColor;
          position: absolute;
          display: block;
          width: 100%;
          height: 100%;
          transition: all 1s;
          left: 0;
          right: 0;
          opacity: 0;
      }
      .is-light.is-on .bubble-icon-container::after {
          opacity: 0.2;
      }
      .is-unavailable.is-light .bubble-icon-container::after {
          opacity: 0;
      }

      .bubble-icon {
          display: flex;
          opacity: 0.6;
      }

      .is-on .bubble-icon {
        filter: brightness(1.1);
        opacity: 1;
      }

      .bubble-entity-picture {
          background-size: cover;
          background-position: center;
          height: 100%;
          width: 100%;
          position: absolute;
      }

      .bubble-name,
      .bubble-state {
          display: flex;
          position: relative;
          white-space: nowrap;
      }

      .bubble-name-container {
          display: flex;
          line-height: 18px;
          flex-direction: column;
          justify-content: center;
          flex-grow: 1;
          margin: 0 160px 0 4px;
          pointer-events: none;
          position: relative;
          overflow: hidden;
      }

      .bubble-name {
          font-size: 25px;
          font-weight: 600;
      }

      .bubble-state {
          font-size: 12px;
          font-weight: normal;
          opacity: 0.7;
      }

      .bubble-feedback-element {
          position: absolute;
          top: 0;
          left: 0;
          opacity: 0;
          width: 100%;
          height: 100%;
          background-color: rgb(0,0,0);
          pointer-events: none;
      }

      @keyframes tap-feedback {
          0% {transform: translateX(-100%); opacity: 0;}
          64% {transform: translateX(0); opacity: 0.1;}
          100% {transform: translateX(100%); opacity: 0;}
      }

      .large .bubble-button-card-container {
        height: 56px;
        border-radius: 32px;
      }

      .large .bubble-icon-container {
        --mdc-icon-size: 40px;
        min-width: 42px !important;
        min-height: 42px !important;
        margin-left: 150px;
      }

      .rows-2 .bubble-sub-button-container {
        flex-direction: column;
        gap: 4px !important;
        display: grid !important;
        grid-template-columns: repeat(2, min-content);
        grid-template-rows: repeat(2, 1fr);
        grid-auto-flow: column;
        width: auto;
        padding-right: 14px;
      }

      .rows-2 .bubble-sub-button {
        height: 20px !important;
      }
  .bubble-button-card-container {
    background: rgba(12,120,50,0.5) !important;
  }     
card_mod:
  style: |
    ha-card {
     --primary-text-color: grey;
     --ha-card-background: #;
     font-size: 100px;
     border-radius: 15px;
     box-shadow: rgba(195, 255, 104, 1) 0px 1px 50px;
     }

I cant find a reference for box_shadow in the buttons styles.ts

Thats why I try to make card_mod work, does noone use box_shadow in combination with bubble-card and could lend me a hand ?

Hey everyone, short questions. Does someone use custom layout card / grid card in the popup card? I am trying to do that because I want to control the layout on my different device (tablet, pc and smartphone) because 3 tile cards are “to much” for my smartphone, but I am not sure how to do this…

First try, I can control the position of the cards, but I am not able to scroll inside the popup and some cards are cut of:

type: vertical-stack
cards:
  - type: custom:layout-card
    layout_type: custom:grid-layout
    layout:
      grid-gap: 1px 1px
      grid-template-columns: 25% 25% 25% 25%
      grid-template-rows: auto
      grid-template-areas: |
        "  chips        chips        chips        chips "
        "  navigation1  navigation2  navigation3  navigation4  "
        "  navigation5  navigation6  navigation7  navigation8  "
        "  navigation9  navigation10 navigation11 navigation12 "
        "  t2           t2           t3           t3           "
        "  person1      person2      .            .            "
      mediaquery:
        '(max-width: 800px)':
          grid-gap: 1px 1px
          grid-template-columns: 50% 50%
          grid-template-areas: |
            "  chips        chips        "
            "  navigation1  navigation2  "
            "  navigation3  navigation4  "
            "  navigation5  navigation6  "
            "  navigation7  navigation8  "
            "  navigation9  navigation10 "
            "  navigation11 navigation12 "
            "  t2           t2           "
            "  t3           t3           "
            "  person1      person2      "
        '(max-width: 1200px)':
          grid-gap: 1px 1px
          grid-template-columns: 33% 33% 33%
          grid-template-areas: |
            "  chips        chips        chips        "
            "  navigation1  navigation2  navigation3  "
            "  navigation4  navigation5  navigation6  "
            "  navigation7  navigation8  navigation9  "
            "  navigation10 navigation11 navigation12 "
            "  t2           t2           t2           "
            "  t3           t3           t3           "
            "  person1      person2      .            "
    cards:
      - type: custom:bubble-card
        card_type: pop-up
        hash: '#fenster3'
        name: Fenster
        icon: mdi:window-open-variant
        styles: ''
        width_desktop: 100%
        show_header: true
        button_type: name
        view_layout:
          grid-area: chips
        card_layout: large
      - type: tile
        entity: cover.wohnzimmer_fenster_kuche
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation1
      - type: tile
        entity: cover.wohnzimmer_fenster_rechts
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation2
      - type: tile
        entity: cover.wohnzimmer_fenster_links
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation3
      - type: tile
        entity: cover.wohnzimmer_fenster_mitte
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation4
      - type: tile
        entity: cover.wohnzimmer_schiebetur
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation5

Second try is this. I can scroll but the grid layout has no effect to the cards:

type: custom:layout-card
layout_type: custom:grid-layout
layout:
  grid-gap: 1px 1px
  grid-template-columns: 25% 25% 25% 25%
  grid-template-rows: auto
  grid-template-areas: |
    "  chips        chips        chips        chips "
    "  navigation1  navigation2  navigation3  navigation4  "
    "  navigation5  navigation6  navigation7  navigation8  "
    "  navigation9  navigation10 navigation11 navigation12 "
    "  t2           t2           t3           t3           "
    "  person1      person2      .            .            "
  mediaquery:
    '(max-width: 800px)':
      grid-gap: 1px 1px
      grid-template-columns: 50% 50%
      grid-template-areas: |
        "  chips        chips        "
        "  navigation1  navigation2  "
        "  navigation3  navigation4  "
        "  navigation5  navigation6  "
        "  navigation7  navigation8  "
        "  navigation9  navigation10 "
        "  navigation11 navigation12 "
        "  t2           t2           "
        "  t3           t3           "
        "  person1      person2      "
    '(max-width: 1200px)':
      grid-gap: 1px 1px
      grid-template-columns: 33% 33% 33%
      grid-template-areas: |
        "  chips        chips        chips        "
        "  navigation1  navigation2  navigation3  "
        "  navigation4  navigation5  navigation6  "
        "  navigation7  navigation8  navigation9  "
        "  navigation10 navigation11 navigation12 "
        "  t2           t2           t2           "
        "  t3           t3           t3           "
        "  person1      person2      .           "
cards:
  - type: vertical-stack
    cards:
      - type: custom:bubble-card
        card_type: pop-up
        hash: '#fenster4'
        name: Fenster
        icon: mdi:window-open-variant
        styles: ''
        width_desktop: 100%
        show_header: true
        button_type: name
      - type: tile
        entity: cover.wohnzimmer_fenster_kuche
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation1
      - type: tile
        entity: cover.wohnzimmer_fenster_rechts
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation2
      - type: tile
        entity: cover.wohnzimmer_fenster_links
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation3
      - type: tile
        entity: cover.wohnzimmer_fenster_mitte
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation4
      - type: tile
        entity: cover.wohnzimmer_schiebetur
        features:
          - type: cover-open-close
          - type: cover-position
        view_layout:
          grid-area: navigation5

I am using the custom grid layout in my old dashboard without any issue, but there is the whole “tab” from the dashboard the layout. I want to use the “new” sections in my new dashboard and only in the popup card the grid layout.

Hi @ddkedr

I just build it to run for bubble-card. But I don’t really like it yet.

type: grid
cards:
  - type: custom:button-card
    name: Wohnzimmer
    icon: mdi:sofa
    tap_action:
      action: navigate
      navigation_path: '#wohnzimmer'
    show_state: true
    custom_fields:
      state: >
        [[[ return states['sensor.wohnzimmer_temperatur'].state + '°C • ' +
        states['sensor.wohnzimmer_luftfeuchtigkeit'].state + '%' ]]]
      btn:
        card:
          type: custom:mushroom-chips-card
          chips:
            - type: template
              icon: mdi:weather-windy
              entity: input_boolean.lueften_wohnzimmer
              card_mod:
                style: |
                  ha-card {
                    --chip-background: {{ 'var(--accent-color)' if is_state('input_boolean.lueften_wohnzimmer', 'on') else 'var(--background-color-2)' }};
                    padding: 5px !important;
                    border-radius: 100px !important; 
                  }
            - type: template
              icon: phu:apple-tv
              entity: media_player.apple_tv
              card_mod:
                style: |
                  ha-card {
                    --chip-background: {{ 'var(--green-color)' if is_state('media_player.apple_tv', 'playing') else 'var(--background-color-2)' }};
                    padding: 5px !important;
                    border-radius: 100px !important; 
                  }
            - type: template
              icon: mdi:window-closed-variant
              entity: group.alle_wohnzimmerfenster
              card_mod:
                style: |
                  ha-card {
                    --chip-background: {{ 'var(--accent-color)' if is_state('group.alle_wohnzimmerfenster', 'on') else 'var(--background-color-2)' }};
                    padding: 5px !important;
                    border-radius: 100px !important; 
                  }
            - type: template
              icon: mdi:window-shutter
              entity: group.alle_wohnzimmerrollladen
              card_mod:
                style: |
                  ha-card {
                    --chip-background: {{ 'var(--accent-color)' if is_state('group.alle_wohnzimmerrollladen', 'open') else 'var(--background-color-2)' }};
                    padding: 5px !important;
                    border-radius: 100px !important; 
                  }
    styles:
      grid:
        - grid-template-areas: '"n btn" "state btn" "i btn"'
        - grid-template-columns: 1fr min-content
        - grid-template-rows: min-content min-content min-content 1fr
      card:
        - padding: 22px 8px 22px 22px
        - height: 250px
        - width: 250px
        - background: var(--card-background-color)
      custom_fields:
        state:
          - justify-self: start
          - font-size: 14px
          - opacity: '0.7'
          - padding-top: 2px
        btn:
          - justify-content: end
          - align-self: start
      name:
        - justify-self: start
        - align-self: start
        - font-size: 18px
        - font-weight: 500
      img_cell:
        - justify-content: start
        - position: absolute
        - width: 180px
        - height: 180px
        - left: 0
        - bottom: 0
        - margin: 0 0 -20px -20px
        - background: var(--orange-color)
        - opacity: '0.5'
        - border-radius: 500px
      icon:
        - position: relative
        - width: 100px
        - color: deep-orange
        - opacity: '0.5'

2 Likes

Hi @Cloos!

Thanks for sharing your Bubble Card.

I didn’t see an example on the GitHub page. How can the play-pause text color be changed in the media player card?

media-player

I’ve tried the following, but no dice.

.bubble-play-pause-button {
  color: 'var(--base)' !important;
 }

Much appreciated!

EDIT: Never mind… I found your post earlier in the thread. I should have omitted the quotes and left off the !important.

How can i change the color of a button card. The colors are now different. One is a light entity en the other is a switch entity

image

How to use an input_text to influence on the color of sub-buttons?

styles: |
  .Bureau > .bubble-icon {
    color: rgba(100,90,120,0.9) !important;
  }
  .Cuisine > .bubble-icon {
    color: red !important;
  } 
  .Salon > .bubble-icon {
    color: {{ states('input_text.couleur_salon') }} !important;
  }

As you can see if I use ‘red’ or a rgba value then it works as expected.

But if I try to insert the value of an input text, it doesn’t work anymore:

{{ states('input_text.couleur_salon') }}
or
{{ state_attr('input_text.couleur_salon','pattern') }}

Any idea of how to dynamic link the color to the input?

Merci

Try color: ${hass.states['input_text.couleur_salon'].state} !important;

2 Likes