Hi,
Your buttons look really good. Can you show us the source code?
Thx
Hi,
Your buttons look really good. Can you show us the source code?
Thx
I’m working on my button, I have a smal problem with my text and sub-button text.
Since the background is reflecting the current illumination level of that room and changes the text colour to be readable, I was hoping to expand this to the text and sub-button text.
If someone could point out how to add the dynamic text colouring based on the illumination level that would be great.
type: custom:bubble-card
card_type: button
entity: light.lights_livingroom
name: Living room
icon: mdi:sofa
tap_action:
action: toggle
double_tap_action:
action: none
hold_action:
action: more-info
button_action:
tap_action:
action: navigate
navigation_path: "#Livingroom"
sub_button:
- entity: switch.livingroom_socket
show_background: false
icon: mdi:power-socket-eu
- entity: sensor.count_lights_living_room
show_background: false
show_state: true
- entity: sensor.living_room_temperature_sensor_humidity
show_background: false
show_state: true
- entity: sensor.living_room_temperature_sensor_temperature
show_attribute: false
show_icon: true
show_state: true
show_background: false
styles: >-
/* General Button Styling */ .bubble-button-card-container {
background: ${
hass.states['light.lights_livingroom'].state === 'on' || hass.states['switch.livingroom_socket'].state === 'on'
? hass.states['light.lights_livingroom'].attributes.rgb_color
? `linear-gradient(
to bottom,
rgba(${hass.states['light.lights_livingroom'].attributes.rgb_color.join(', ')}, 0.6),
rgba(${hass.states['light.lights_livingroom'].attributes.rgb_color.map(c => c * 0.5).join(', ')}, 0.6),
rgba(${hass.states['light.lights_livingroom'].attributes.rgb_color.map(c => c * 0.6).join(', ')}, 0.6))`
: 'linear-gradient(to bottom, rgba(80,80,0,0.9), rgba(20,20,20,0.9), rgba(80,60,0,0.9))'
: (()=>{
const illuminance = parseFloat(hass.states['sensor.living_room_presence_illuminance'].state);
let bgGradient;
// Map illuminance (lux) to background gradient
if (illuminance <= 0) {
bgGradient = 'linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(10, 10, 10, 0.8))';
} else if (illuminance <= 10) {
bgGradient = 'linear-gradient(to bottom, rgba(20, 10, 5, 1), rgba(40, 20, 10, 0.8))';
} else if (illuminance <= 50) {
bgGradient = 'linear-gradient(to bottom, rgba(50, 25, 15, 1), rgba(100, 50, 30, 0.8))';
} else if (illuminance <= 200) {
bgGradient = 'linear-gradient(to bottom, rgba(120, 80, 40, 1), rgba(180, 120, 80, 0.8))';
} else if (illuminance <= 500) {
bgGradient = 'linear-gradient(to bottom, rgba(180, 140, 80, 1), rgba(220, 180, 120, 0.8))';
} else if (illuminance <= 1000) {
bgGradient = 'linear-gradient(to bottom, rgba(220, 200, 160, 1), rgba(240, 220, 200, 0.8))';
} else if (illuminance <= 5000) {
bgGradient = 'linear-gradient(to bottom, rgba(240, 240, 220, 1), rgba(255, 255, 240, 0.8))';
} else if (illuminance <= 10000) {
bgGradient = 'linear-gradient(to bottom, rgba(255, 255, 250, 1), rgba(255, 255, 255, 0.8))';
} else {
bgGradient = 'linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.8))';
}
return bgGradient;
})()
} !important;
border: 4px solid ${
hass.states['light.lights_livingroom'].state === 'on' || hass.states['switch.livingroom_socket'].state === 'on'
? hass.states['light.lights_livingroom'].attributes.rgb_color
? `rgba(${hass.states['light.lights_livingroom'].attributes.rgb_color.join(', ')}, 0.8)`
: 'rgba(200, 150, 50, 0.8)'
: 'rgba(100,100,100,0.6)'
} !important;
box-sizing: border-box;
}
.bubble-button-background {
background: rgba(0,0,0,0) !important;
}
/* Icon and Text Color Styling */ .bubble-icon, .bubble-entity-state {
color: ${
hass.states['light.lights_livingroom'].state === 'on' || hass.states['switch.livingroom_socket'].state === 'on'
? hass.states['light.lights_livingroom'].attributes.rgb_color
? `rgba(${hass.states['light.lights_livingroom'].attributes.rgb_color.map(c => c * 0.7).join(', ')}, 1)` /* Darker shade of light color */
: 'rgba(255, 255, 20, 1)'
: (()=>{
const illuminance = parseFloat(hass.states['sensor.living_room_presence_illuminance'].state);
let textColor;
// Map illuminance (lux) to text color
if (illuminance <= 0) {
textColor = 'rgba(255, 255, 255, 1)'; // Light text for very dark environment
} else if (illuminance <= 50) {
textColor = 'rgba(255, 255, 255, 1)'; // Light text
} else if (illuminance <= 200) {
textColor = 'rgba(0, 0, 0, 1)'; // Dark text for medium light
} else {
textColor = 'rgba(0, 0, 0, 0.9)'; // Dark text for high light
}
return textColor;
})()
} !important;
}
.bubble-icon-container {
background: rgba(0, 0, 0, 0) !important;
}
/* Dynamic humidity colour styling */
${(() => {
const humidity = parseFloat(hass.states['sensor.living_room_temperature_sensor_humidity']?.state || 0);
let color, icon;
if (humidity < 30) {
color = 'rgba(210,180,140,0.8)'; // Light Brown (very dry)
icon = 'mdi:water-percent-alert';
} else if (humidity < 40) {
color = 'rgba(222,184,135,0.8)'; // Burlywood (dry)
icon = 'mdi:water-percent';
} else if (humidity <= 60) {
color = 'rgba(152,251,152,0.8)'; // Pale Green (optimal)
icon = 'mdi:water-percent';
} else if (humidity < 70) {
color = 'rgba(173,216,230,0.8)'; // Light Blue (humid)
icon = 'mdi:water-percent';
} else {
color = 'rgba(135,206,250,0.8)'; // Light Sky Blue (very humid)
icon = 'mdi:water-percent-alert';
}
const subButton = card.querySelector('.bubble-sub-button-3');
if (subButton) {
const iconElement = subButton.querySelector('ha-icon');
iconElement.style.color = color;
iconElement.setAttribute('icon', icon);
}
})()}
/* Dynamic temperature colour styling */
${(() => {
const temperature = parseFloat(hass.states['sensor.living_room_temperature_sensor_temperature']?.state || 0);
let color;
if (temperature <= 0) {
color = 'rgba(0,0,139,0.8)'; // Dark Blue (very cold)
} else if (temperature <= 5) {
color = 'rgba(0,71,171,0.8)'; // Cobalt Blue (cold)
} else if (temperature <= 10) {
color = 'rgba(30,144,255,0.8)'; // Dodger Blue (cool)
} else if (temperature <= 15) {
color = 'rgba(100,149,237,0.8)'; // Cornflower Blue (cool)
} else if (temperature <= 20) {
color = 'rgba(60,179,113,0.8)'; // Medium Sea Green (comfortable)
} else if (temperature <= 23) {
color = 'rgba(152,251,152,0.8)'; // Pale Green (comfortable)
} else if (temperature <= 26) {
color = 'rgba(255,223,186,0.8)'; // Peach (warm)
} else if (temperature <= 28) {
color = 'rgba(255,215,0,0.8)'; // Gold (hot)
} else if (temperature <= 35) {
color = 'rgba(178,34,34,0.8)'; // Firebrick Red
} else {
color = 'rgba(139,0,0,0.8)'; // Dark Red (extremely hot)
}
const subButton = card.querySelector('.bubble-sub-button-4');
if (subButton) {
subButton.querySelector('ha-icon').style.color = color;
}
})()}
/* Hide inactive sub-button */
${(() => {if(hass.states['switch.livingroom_socket'].state !=
'on'){card.querySelector('.bubble-sub-button-1').classList.add("hidden")}})()}
${(() => {if(hass.states['light.lights_livingroom'].state !=
'on'){card.querySelector('.bubble-sub-button-2').classList.add("hidden")}})()}
I have the pop-up button.
Where I don’t need the light colours, the text works here, but this method fails in the one above.
And I can’t get the colouring applied to the sub-button text
type: custom:bubble-card
card_type: pop-up
hash: "#Livingroom"
button_type: state
entity: sensor.living_room_presence_illuminance
show_header: true
name: Living room
icon: mdi:sofa
scrolling_effect: true
sub_button:
- entity: sensor.living_room_temperature_sensor_humidity
show_background: false
show_state: true
- entity: sensor.living_room_temperature_sensor_temperature
show_state: true
show_background: false
styles: |-
/* General Button Styling */
.bubble-icon-container {
background: rgba(0, 0, 0, 0) !important;
}
/* Illumination Styling */
${(() => {
const illuminance = parseFloat(hass.states['sensor.living_room_presence_illuminance'].state);
let bgGradient, borderColor, textColor, iconColor;
// Map illuminance (lux) to background gradient, border, text, and icon colors based on real-world light perception
if (illuminance <= 0) {
bgGradient = 'linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(10, 10, 10, 0.8))';
borderColor = 'rgba(50, 50, 50, 0.8)';
textColor = 'rgba(255, 255, 255, 1)';
iconColor = 'rgba(255, 255, 255, 1)'; // White icon for low light
} else if (illuminance <= 10) {
bgGradient = 'linear-gradient(to bottom, rgba(20, 10, 5, 1), rgba(40, 20, 10, 0.8))';
borderColor = 'rgba(80, 40, 20, 0.8)';
textColor = 'rgba(255, 220, 180, 1)';
iconColor = 'rgba(255, 220, 180, 1)'; // Warm icon color
} else if (illuminance <= 50) {
bgGradient = 'linear-gradient(to bottom, rgba(50, 25, 15, 1), rgba(100, 50, 30, 0.8))';
borderColor = 'rgba(120, 60, 40, 0.8)';
textColor = 'rgba(255, 230, 200, 1)';
iconColor = 'rgba(255, 230, 200, 1)'; // Soft warm icon color
} else if (illuminance <= 200) {
bgGradient = 'linear-gradient(to bottom, rgba(120, 80, 40, 1), rgba(180, 120, 80, 0.8))';
borderColor = 'rgba(160, 120, 80, 0.8)';
textColor = 'rgba(255, 255, 230, 1)';
iconColor = 'rgba(255, 255, 230, 1)'; // Bright icon color
} else if (illuminance <= 500) {
bgGradient = 'linear-gradient(to bottom, rgba(180, 140, 80, 1), rgba(220, 180, 120, 0.8))';
borderColor = 'rgba(200, 180, 140, 0.8)';
textColor = 'rgba(0, 0, 0, 1)';
iconColor = 'rgba(0, 0, 0, 1)'; // Black icon for high contrast
} else if (illuminance <= 1000) {
bgGradient = 'linear-gradient(to bottom, rgba(220, 200, 160, 1), rgba(240, 220, 200, 0.8))';
borderColor = 'rgba(240, 220, 200, 0.8)';
textColor = 'rgba(0, 0, 0, 1)';
iconColor = 'rgba(0, 0, 0, 1)'; // Black icon
} else if (illuminance <= 5000) {
bgGradient = 'linear-gradient(to bottom, rgba(240, 240, 220, 1), rgba(255, 255, 240, 0.8))';
borderColor = 'rgba(255, 255, 240, 0.8)';
textColor = 'rgba(0, 0, 0, 1)';
iconColor = 'rgba(0, 0, 0, 1)'; // Black icon
} else if (illuminance <= 10000) {
bgGradient = 'linear-gradient(to bottom, rgba(255, 255, 250, 1), rgba(255, 255, 255, 0.8))';
borderColor = 'rgba(255, 255, 255, 0.8)';
textColor = 'rgba(0, 0, 0, 1)';
iconColor = 'rgba(0, 0, 0, 1)'; // Black icon
} else {
bgGradient = 'linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.8))';
borderColor = 'rgba(255, 255, 255, 0.8)';
textColor = 'rgba(0, 0, 0, 1)';
iconColor = 'rgba(0, 0, 0, 1)'; // Black icon for very bright sunlight
}
// Apply the background gradient, border, and text color dynamically
const container = card.querySelector('.bubble-button-card-container');
if (container) {
container.style.background = bgGradient;
container.style.border = `4px solid ${borderColor}`;
container.style.color = textColor;
container.style.boxSizing = 'border-box';
}
// Update the icon color dynamically
const iconElement = card.querySelector('.bubble-icon');
if (iconElement) {
iconElement.style.color = iconColor;
}
// Apply text color to sub-buttons
setTimeout(() => {
const subButtons = card.querySelectorAll('.bubble-sub-button');
subButtons.forEach(button => {
const stateElement = button.querySelector('.bubble-sub-button-state');
if (stateElement) {
stateElement.style.setProperty('color', textColor, 'important');
}
});
}, 100);
return '';
})()}
/* Humidity Styling */
${(() => {
const humidity = parseFloat(hass.states['sensor.living_room_temperature_sensor_humidity'].state);
let color;
let icon = 'mdi:water-percent';
if (humidity < 30) {
color = 'rgba(210,180,140,0.8)';
icon = 'mdi:water-percent-alert';
} else if (humidity < 40) {
color = 'rgba(222,184,135,0.8)';
icon = 'mdi:water';
} else if (humidity <= 60) {
color = 'rgba(152,251,152,0.8)';
} else if (humidity < 70) {
color = 'rgba(173,216,230,0.8)';
icon = 'mdi:water';
} else {
color = 'rgba(135,206,250,0.8)';
icon = 'mdi:water-percent-alert';
}
const subButton = card.querySelector('.bubble-sub-button-1');
if (subButton) {
const iconElement = subButton.querySelector('ha-icon');
if (iconElement) {
iconElement.style.color = color;
iconElement.setAttribute('icon', icon);
}
}
})()}
/* Temperature Styling */
${(() => {
const temperature = parseFloat(hass.states['sensor.living_room_temperature_sensor_temperature'].state);
let color;
if (temperature <= 0) {
color = 'rgba(0,0,139,0.8)';
} else if (temperature <= 5) {
color = 'rgba(0,71,171,0.8)';
} else if (temperature <= 10) {
color = 'rgba(30,144,255,0.8)';
} else if (temperature <= 15) {
color = 'rgba(100,149,237,0.8)';
} else if (temperature <= 20) {
color = 'rgba(60,179,113,0.8)';
} else if (temperature <= 23) {
color = 'rgba(152,251,152,0.8)';
} else if (temperature <= 26) {
color = 'rgba(255,223,186,0.8)';
} else if (temperature <= 28) {
color = 'rgba(255,215,0,0.8)';
} else if (temperature <= 35) {
color = 'rgba(178,34,34,0.8)';
} else {
color = 'rgba(139,0,0,0.8)';
}
const subButton = card.querySelector('.bubble-sub-button-2');
if (subButton) {
const icon = subButton.querySelector('ha-icon');
if (icon) {
icon.style.color = color;
}
}
})()}
Thank you very much
Is there a way to center the heading instead of having it on the left?
I haven’t found any option or documentation to do so.
Is there a way to make the swipe to close on the popup card shorter for how far you have to touch and drag your finger? Instead of being a long swipe, that it be more of a flick akin to gesture navigation? Looking to use popups with navigation buttons glued to the bottom of the screen and have the swipes act more like the gesture navigation in iOS. I’ve searched the thread, but haven’t seen any posts on it. While touch to close is an option, it isn’t intuitive for people that use iOS.
mind sharing how you do this please?
Hi! There is an option to change the sliding distance, but in the next release it will be finally possible to slide from the header of the pop-up to close it, this was working on Android but I’ve finally fixed this for iOS!
Ah! Thanks for that. Sorry I missed that option. This should fit my use case well then. Thanks!
Hi! Nice job! Is there a way to do this with sub-buttons?
Try to add this to your styling options
.bubble-name-container{
align-items: center;
}
You just add a sub-button with a random entity, disable all the switches except “Show name”, and type space " "
as your custom sub-button name:
YAML should look like this:
- show_icon: false
show_name: true
name: " "
state_background: false
show_background: false
And that’s how it’s going to look:
hej @nesnajkneh
to your questions (I hope u have solved it in teh meantime… )
I guess you dont have a device “LOCK” with FEATURE " main_door" ? thats teh inidcator I use to trigger the change in colors. Use a feature that exists in your system.
hope this helpd
I’m trying to implement a popup remote for sky Q, currently using mini media player, but am having trouble, the sky Q intergration remote operates on a shortcuts basis, but for the life of me I can’t get this working in bubble card media player, does anyone know if this is possible?
Managed to sort this installing sky remote integrati9n and creating lots of scripts
Is there an option or workaround to select multiple items in the select card?
In all of my button pop-up cards there’s a blank space below the cards, so you can scroll downwards. Is there a way to fix this to make it not ‘scrollable’? Thanks in advance!
Will you share the code please?
I can’t take full credit! Most of it came from here - https://www.reddit.com/r/homeassistant/comments/1ifj7ph/woo_hoo_newbie_success/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
He has posted a link to his Yaml, I just did a fair few changes
Has anyone created a nice dashboard for tablet with bubble cards ? Really interested in some inspiration
Kr,
Bart
Nice! I wonder if it would be possible to show a conditional icon instead of content: "{{ states('sensor.day_length') }}";
…