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

updates did not fix this error btw.

Hi! Can you open an issue here please?

Please provide the more information your can, I haven’t this issue on my side so I need to be able to reproduce it so that I can fix it :slightly_smiling_face:

sure thing!

Could it be possible with the horizontal-stack-buttons, have a button that can toggle the sidebar if it is hidden?


I got this far with this wonderful card. Really loving it. Now I’m kind of stuck. Can’t find how to remove the pill? background of those subbuttons. Also, everytime I open the code-editor, the main subbutton (HVAC mode) piece of code returns automatically. Suggestions? :slight_smile:


Can anyone help with some basic yaml or advice on how to achieve the example with a slider and button in a row that Cloos has on his dashboard?

I think I am missing something obvious but can’t figure it out.

Thanks

Hi,

I have a few bubble cards with the small sub buttons. See screenshot below.

Is it possible to have those small sub buttons as you can see in the “Rest & Biomüll” card, and then have another row with bigger sub buttons as you can see in the “Lademodus” card?

The small sub buttons (“In 8 Tagen”, “in 26 Tagen” etc.) are supposed to be used for information only, and than I would like to have 3-5 separate bigger sub buttons in a row below.

I tried creating groups, but wasn’t able to achieve what I want to achieve. Maybe I’m missing something.

Thanks in advance!

Edit: Not sure if that will work with bubble card on its own. I have now used a stack-in-card and with that I can achieve that:

Has anyone been using Local Condition Card GitHub - PiotrMachowski/Home-Assistant-Lovelace-Local-Conditional-card: This card can show and hide a specific card on current device while not affecting other windows. It does not require any integration to run. · GitHub with the bubble card. I’m using Local Condition Card to have tabs but since 2026.x changes to HA, when I have the horizonal buttons stack the Save and Cancel buttons are hidden and I cannot save any changes. It works fine, if I remove the horizonal stack card.

I’m having a problem with my bubble cards. When I try to edit them in the editor, they keep getting longer and Safari or Chrome freezes. I can’t edit anything.

type: custom:bubble-card
card_type: button
entity: sensor.raumthermostat_temperature
show_attribute: false
show_name: true
show_icon: true
scrolling_effect: true
show_state: true
double_tap_action:
  action: navigate
  navigation_path: "#szenenWZ"
card_layout: large-2-rows
button_action:
  tap_action:
    action: navigate
    navigation_path: "#wohnzimmer"
tap_action:
  action: navigate
  navigation_path: "#wohnzimmer"
button_type: state
name: Wohnzimmer
icon: "no"
sub_button:
  main:
    - entity: light.wohnzimmer
      show_last_changed: false
      show_attribute: false
      show_state: false
      tap_action:
        action: toggle
      show_background: true
      hold_action: {}
      double_tap_action: {}
      name: Lampen Wohnzimmer
    - show_last_changed: false
      show_state: false
      show_name: false
      tap_action:
        action: toggle
      entity: input_boolean.1
      double_tap_action:
        action: navigate
        navigation_path: "#mediaplayerwohnzimmer"
      icon: ""
      name: Sonos Wohnzimmer
    - entity: switch.lichterkette_balkon
      tap_action:
        action: toggle
      double_tap_action: {}
      hold_action: {}
      name: Lichterkette Balkon
    - entity: switch.steckdose_sterne
      tap_action:
        action: toggle
      double_tap_action:
        action: {}
      hold_action:
        action: {}
      name: Sterne Lichterkette
  bottom: []
styles: >
  :host{
      --icon-Background-Color: rgba(79, 148, 205, 0.4);
      --color-yellow: 255, 202, 58;
      --color-blue: 25, 130, 196;
      --color-green: 138, 201, 38;
      --color-purple: 106, 76, 147;
      --color-purple1: 233, 53, 157;
      --color-blue1: 53, 205, 233;
  }

  .card-content {
    width: 100%;
    margin: 0 !important;
  }

  .large .bubble-button-card-container {
    height: calc(var(--row-height) * var(--row-size) + var(--row-gap) * (var(--row-size) - 1)) !important;
    overflow: hidden !important;
    background: rgba(30, 30, 30, 0.5) !important;
    backdrop-filter: blur(12px) !important;
    -webkit-backdrop-filter: blur(12px) !important;
    border-radius: 25px !important;
    border: 1px solid rgba(255, 255, 255, 0.1);
  }

  .bubble-button-card {
    display: grid;
    grid-template-areas:
      'n n n b'
      'l l l b'
      'i i . b'
      'i i . b';
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-rows: 1.5fr 0.5fr 1fr 1fr;
    justify-items: center;
    position: relative;
  }

  .bubble-icon-container {
    grid-area: i;
    border-radius: 50% !important;
    width: 160% !important;
    height: 160% !important;
    max-width: none !important;
    max-height: none !important;
    position: absolute !important;
    place-self: center !important;
    margin: 0px 0px 0px 0px !important;
    padding: 0px, 0px, 0px, 0px !important;
    background-color: var(--icon-Background-Color);
    background-image: url("/local/interior-design.png") !important;
    background-size: 50%;
    background-repeat: no-repeat;
    background-position: 50% 40%;
  }

  .bubble-icon {
    width: 0%;
    position: relative !important;
    --mdc-icon-size: 100px !important;
    opacity: 0.5 !important;
  }

  .bubble-name-container {
    grid-area: n;
    justify-self: start;
    margin-left: 20px;
    max-width: calc(100% -(12px + 0px));
    gap: 10px !important;
    color: #fffefd;
  }

  .bubble-name {
    font-weight: bold;
    font-size: 19px;
  }

  .bubble-state {
    font-weight: bold;
    font-size: 14px;
    filter: opacity(70%);
  }

  .bubble-state::before {
    content: "🌡️";
    margin-right: 5px;
  }

  .rows-2 .bubble-sub-button-container {
    grid-area: b;
    display: flex !important;
    flex-wrap: wrap;
    flex-direction: column;
    gap: calc((100% - 4 * 36px)/5) !important;
    justify-content: flex-start;
    width: auto !important;
    right: 0px !important;
    padding-right: 0px !important;
    height: 100% !important;
    top: calc((100% - 4 * 36px)/5) !important;
  }

  .rows-2 .bubble-sub-button {
    height: 36px !important;
    width: 36px !important;
    padding: 0 !important;
    margin: 0 !important;
    background: rgba(255, 255, 255, 0.05) !important;
    backdrop-filter: blur(6px) !important;
    border-radius: 50% !important;
    transition: all 0.3s ease;
  }

  .rows-2 .bubble-sub-button:hover {
    background: rgba(255, 255, 255, 0.15) !important;
    transform: scale(1.1);
  }

  .bubble-sub-button {
    min-width: 36px !important;
  }

  .bubble-sub-button-1 {
    background-color: rgba(var(${hass.states['light.wohnzimmer'].state === 'on' ? '--color-yellow' : '255,255,255'}), 0.3) !important;
    box-shadow: ${hass.states['light.wohnzimmer'].state === 'on' ? '0 0 12px rgba(var(--color-yellow), 0.8)' : 'none'} !important;
    color: rgba(var(${hass.states['light.wohnzimmer'].state === 'on' ? '--color-yellow' : '255,255,255'}), 1) !important;
  }

  .bubble-sub-button-2 {
    color: rgba(var(${hass.states['input_boolean.1'].state === 'on' ? '--color-blue1' : '255,255,255'}), 1) !important;
    background-color: rgba(var(${hass.states['input_boolean.1'].state === 'on' ? '--color-blue1' : '255,255,255'}), 0.3) !important;
    box-shadow: ${hass.states['input_boolean.1'].state === 'on' ? '0 0 12px rgba(var(--color-blue1), 0.8)' : 'none'} !important;
  }

  .bubble-sub-button-2 .bubble-sub-button-icon{
    animation: ${hass.states['input_boolean.1'].state === 'on' ? 'sound 0.8s infinite' : 'none'} !important;
  }

  .bubble-sub-button-3 {
    color: rgba(var(${hass.states['switch.lichterkette_balkon'].state === 'on' ? '--color-purple1' : '255,255,255'}), 1) !important;
    background-color: rgba(var(${hass.states['switch.lichterkette_balkon'].state === 'on' ? '--color-purple1' : '255,255,255'}), 0.3) !important;
    box-shadow: ${hass.states['switch.lichterkette_balkon'].state === 'on' ? '0 0 12px rgba(var(--color-purple1), 0.8)' : 'none'} !important;
  }

  .bubble-sub-button-3 .bubble-sub-button-icon {
    animation: ${hass.states['switch.lichterkette_balkon'].state === 'on' ? 'bounce 0.6s cubic-bezier(0.30, 2.40, 0.85, 2.50) infinite' : 'none'};
  }

  @keyframes bounce { 
    0%, 100% { transform: translateY(0px) scaleY(0.9); }
    80% { transform: translateY(-3px); }
  }

  @keyframes sound {
    0% { transform: scale(1); }
    50% { transform: scale(1.05); }
    100% { transform: scale(1); }
  }

  .bubble-sub-button-4 {
    color: rgba(var(${hass.states['switch.steckdose_sterne'].state === 'on' ? '--color-yellow' : '255,255,255'}), 1) !important;
    background-color: rgba(var(${hass.states['switch.steckdose_sterne'].state === 'on' ? '--color-yellow' : '255,255,255'}), 0.3) !important;
    box-shadow: ${hass.states['switch.steckdose_sterne'].state === 'on' ? '0 0 12px rgba(var(--color-yellow), 0.8)' : 'none'} !important;
  }

  .bubble-sub-button-4 .bubble-sub-button-icon{
    animation: ${hass.states['switch.steckdose_sterne'].state === 'on' ? 'shake 10s infinite' : 'none'} !important;
  }

  @keyframes shake {
    0% { transform: translate(0px, 5px) rotate(0deg); }
    25% { transform: translate(-5px, 0px) rotate(-45deg); }
    50% { transform: translate(0px, -5px) rotate(0deg); }
    75% { transform: translate(5px, 0px) rotate(45deg); }
    100% { transform: translate(0px, 5px) rotate(0deg); }
  }

  ${subButtonIcon[0].setAttribute("icon", hass.states['light.wohnzimmer'].state
  === 'on' ? 'hue:bulb-group-sultan-3' : 'hue:bulb-group-sultan-3-off')}
  ${subButtonIcon[1].setAttribute("icon", hass.states['input_boolean.1'].state
  === 'on' ? 'mdi:speaker-play' : 'mdi:speaker-pause')}
  ${subButtonIcon[2].setAttribute("icon",
  hass.states['switch.lichterkette_balkon'].state === 'on' ? 'hue:festavia' :
  'hue:festavia')} ${subButtonIcon[3].setAttribute("icon",
  hass.states['switch.steckdose_sterne'].state === 'on' ? 'mdi:creation' :
  'mdi:creation-outline')}
force_icon: true
show_last_changed: false
layout_options:
  grid_columns: 2
  grid_rows: 3.5


Hello,
First thanks @Cloos for the great work on this cards ! I really enjoy the customizability

Is there a way to conditionally deactivate a slider ?
Below are screenshots of a bubble-card button to control a light with a slider.
I don’t like when the slider takes over the full button, so I changed that in the styles.

The button tap action is set to nothing, and indeed nothing happens when tapping on the card.

However when the light is off, if you swipe the finger on the card, the light will turn on. Either at minimum brightness or some brightness, depending how you swipe. Despite my best efforts, it seems the slider is still active.

I would like to completely deactivate the slider when the light is off. Is it possible ?
display: none and pointer-events: none are not enough.

When light off, slider hidden

when light on, slider visible with the range background

Code
type: custom:bubble-card
card_type: button
button_type: slider
entity: light.lampe_1
tap_action:
  action: toggle
button_action:
  tap_action:
    action: none
  hold_action:
    action: none
show_state: true
show_last_changed: false
show_attribute: true
show_background: false
attribute: brightness
slider_value_position: left
light_slider_type: brightness
step: 10
min_value: 10
max_value: 100
sub_button:
  main:
    - entity: light.lampe_1
      icon: mdi:information
      state_background: false
      show_background: false
      content_layout: icon-left
  bottom: []
rows: 1
card_layout: large
styles: |
  /* ── Brightness Slider ── */
  /* ── 1. card container position relative ── */
  /* It is relative by default. This is just to ensure */
  .bubble-button-card-container {
    position: relative !important; 
  }

  /* ── 2. slider height, position and display ── */
  .bubble-range-slider {
    position: absolute !important;
    bottom: 2px !important;
    top: auto !important;
    left: 60px !important;
    right: 56px !important;
    width: auto !important;
    height: 10px !important;
    border-radius: 5px !important;    
    
    /* show range background */
    background: rgba(16.8, 16.8, 16.8, 0.8) !important;
    
    /* hide slider when light is off */
    display: ${state === 'on' ? 'flex' : 'none'} !important;
    
    /* attempt to deactivate slider when light is off */
    pointer-events: ${state === 'on' ? 'auto' : 'none'} !important;
  }

  /* ── 3. slider filling ── */
  .bubble-range-fill {
    height: 100% !important;
    border-radius: 0px !important;
  }

Thanks for your input

Everyone who creates a HA wants one thing: the ability to customize it endlessly (I went through hell with the AQARA app)
For me, Bubble Card is the second-best surprise in HA after Frigate.
So a huge THANK YOU for all your hard work.

I’m having an issue.
I created a simple card with my photo and wanted to display my location and phone battery level.

I can’t figure out how to avoid the default HA blue theme.
Or I set state_background: false, but it still doesn’t display the color I chose.

I’d like green when I’m home and red when I’m away.
Same for the battery: red, green, and orange.

Thanks for your help.

type: custom:bubble-card
card_type: button
button_type: state
entity: person.diablojeje91
name: ""
tap_action:
  action: more-info
grid_options:
  columns: 6
card_mod:
  style: |
    ha-card {
      --bubble-sub-button-background-color: transparent !important;
    }
sub_button:
  main:
    - entity: person.diablojeje91
      show_state: true
      show_icon: false
      state_background: true
      styles: |
        .state-home {
          background: rgba(52, 199, 89, 0.9) !important;
          color: white !important;
        }
        .state-not_home {
          background: rgba(255, 59, 48, 0.9) !important;
          color: white !important;
        }
    - entity: sensor.iphone_de_jeremy_battery_level
      show_state: true
      card_layout: normal
      styles: |
        .bubble-sub-button {
         background-color: ${
           hass.states['sensor.iphone_de_jeremy_battery_level'].state < 20
             ? '#C91414'
             : hass.states['sensor.iphone_de_jeremy_battery_level'].state < 50
             ? '#FF7E01'
             : '#75AD6F'
        } !important;
      show_background: false
      show_icon: true
      scrolling_effect: true
      show_attribute: false
      show_last_updated: false
      show_name: false
      force_icon: false
  bottom: []
force_icon: false
show_last_changed: false
show_last_updated: false
show_icon: true
show_name: false
show_state: false

state_background: false

Try this in your entity
It removes the background for me

I also have this before the “Sub” button

card_mod:
  style: |
    ha-card {
      --bubble-sub-button-background-color: transparent !important;
    }

It’s not working :frowning:
; there must be something missing to disable the overlay theme.

hi, i like the bubble cards very much, but i can not find out how to remove the grey background behind the trash can.

tried with claude and gemini, but nothing worked. can someone help me?
Thanks a lot

There is no need for card-mod to alter the styling of bubble-cards and it’s sub-buttons

HACS, Bubble card, documentation ( or examples on the bottom of the page)

Ok those room images are sick. Where did you get them? Any chance you can share?

Hi there,
I’ve updated to HA 2026.4 and having compatibility issues.

The main dashboard, consisting of several popups, is showing a major empty area on the top now

The popup adjustment is broken (especially when the popup requires scrolling due to size) and scrolling is no more possible.

Any ideas?

Edit: I’ve solved the gap by re-arranging the popups (moved them behind all other cards, as described in the popup settings (when did it change from above to below other cards?)), it’s just the scrolling and adjustment of cards in popups which is no longer working.

Edit2: the fix mentioned by cloos below worked for me :+1:

Yea after updating popups are kind of messed up for me depending how many cards I have in the popup it seems, damn.

@RKCKBN @davidnestico Hi! I have a fix and I will release a new version tomorrow, I was not expecting HA 2026.4 to be released today (they usually release it a bit later), I’m sorry for that!

I’ve already posted how to (easily) fix this in the meantime here:

2 Likes