The default tap_action
(there is no default for hold_action
on purpose) for non toggle-able entities is already more-info
. If it’s not the case for you, you have an issue (cache ?)
tbh, can’t imagine, this card has been there since forever…
will take them out again and see what gives.
it uses lovelace gen and there are issues with this version regarding text. I’ve since moved away from this config so I don’t have fixes for them
Also this uses lovelace gen, so you’ll need to remove the jinja stuff and replace it with what’s required in that field.
# lovelace_gen
{% set color = color|default('var(--paper-item-icon-active-color)') %}
type: custom:button-card
aspect_ratio: 1/1
entity: {{ entity }}
size: 60%
name: {{ name }}
show_state: true
show_name: true
show_label: false
styles:
icon:
- height: auto
img_cell:
- justify-content: start
- align-items: start
grid:
- grid-template-areas: '"i info" "n n" "s s" "l l"'
- grid-template-columns: 1fr 35%
- grid-template-rows: 1fr 0.min-content min-content min-content
- position: relative
card:
- border-radius: 15px
- padding: 10px
name:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 12px
- text-align: start
- background-image: linear-gradient(to right, white 0%, white 80%, rgba(0,0,0,0))
- -webkit-background-clip: text
- -webkit-text-fill-color: transparent
- position: relative
- display: inline-block
- width: 100%
- align-content: start
- text-align: start
- text-overflow: unset
state:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 12px
- text-align: start
custom_fields:
info:
- align-self: start
custom_fields:
info: >
[[[
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
}
const length = 41;
const width = 3;
if (entity.state === 'on' && entity.attributes.brightness) {
const radius = length / 2;
const brightness = Math.round(entity.attributes.brightness / 2.54);
const circumference = radius * 2 * Math.PI;
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="none" stroke="var(--paper-item-icon-color)" opacity="0.5" stroke-width="${width}" />
<circle style="
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${circumference};
stroke-dashoffset: ${circumference - brightness / 100 * circumference};
"
id="c_brightness" cx="25" cy="25" r="${radius}" stroke="var(--paper-item-icon-active-color)" stroke-width="${width}" fill="none" stroke-linecap="round" />
<text x="50%" y="54%" fill="var(--primary-text-color)" font-size="14" text-anchor="middle" alignment-baseline="middle">${brightness}<tspan font-size="10">%</tspan>
</text>
</svg>
`;
}
else if (entity.state === 'on' && entity.attributes.speed && entity.attributes.speed_list) {
const text = capitalizeFirstLetter(entity.attributes.speed);
const gap = 5;
const edge = (50 - length) / 2;
const y = 50 - edge;
var items = entity.attributes.speed_list;
if (items.indexOf('off') !== -1){
items.splice(items.indexOf('off'), 1);
}
const current = items.indexOf(entity.attributes.speed)
var i;
var x1 = edge;
var ret = `<svg viewBox="0 0 50 50">`;
var l = (length - gap * (items.length - 1)) / items.length;
for (i = 0; i < items.length; i++) {
var x2 = x1 + l;
var color = (i <= current) ? "var(--paper-item-icon-active-color)" : "var(--paper-item-icon-color)";
var opacity = (i <= current) ? "1.0" : "0.5";
ret += `<line x1="${x1}" y1="${y}" x2="${x2}" y2="${y}" stroke="${color}" stroke-width="${width}" opacity="${opacity}" stroke-linecap="round" />`;
x1 = x2 + gap;
}
ret += `<text x="50%" y="54%" fill="var(--primary-text-color)" font-size="14" text-anchor="middle" alignment-baseline="middle">${text}</text></svg>`
return ret;
}
]]]
state:
- value: 'on'
styles:
card:
- opacity: 1.0
icon:
- color: |
[[[
var [domain, object_id] = entity.entity_id.split('.');
if (domain === "light")
return 'var(--button-card-light-color)';
return '{{ color }}';
]]]
name:
- color: white
state:
- color: gray
lock:
- color: white
label:
- color: gray
- value: 'off'
styles:
card:
- opacity: 0.5
icon:
- color: var(--paper-item-icon-color)
name:
- color: var(--primary-text-color)
state:
- color: var(--primary-text-color)
label:
- color: var(--primary-text-color)
lock:
- color: var(--paper-item-icon-color)
- value: "unavailable"
styles:
card:
- opacity: 0.2
icon:
- color: var(--paper-item-icon-color)')
name:
- color: var(--primary-text-color)
state:
- color: hsl(0, 100%, 50%)
label:
- color: var(--primary-text-color)
lock:
- color: var(--paper-item-icon-color)
tap_action:
action: toggle
haptic: light
hold_action:
action: more-info
haptic: heavy
OK, I finally got this to work. Using the hints from this StackOverflow post, the trick is to make the img_cell
grid item a flexbox container and then specify how all the items of the flex box are to be aligned (in this case the only item is the icon
(ha-icon)).
For some reason, the only way to get this to work was to specify a 1/1
aspect ratio. Not sure why…
Here is the code:
type: 'custom:button-card'
entity: switch.my_switch
name: My Switch
show_state: true
aspect_ratio: '1/1'
icon: mdi:fire
styles:
grid:
- grid-template-areas: '"i" "n" "s"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content min-content
img_cell:
- display: flex
- justify-content: left
name:
- justify-self: start
- padding-left: 10px
- font-weight: bold
- text-transform: lowercase
state:
- justify-self: start
- padding-left: 10px
thanks for your commitment, that works!
button-card has really weird behavior sometimes… and iam really a noob if it comes to css. Is there a solution for a horizontal-stack with 4 button cards and card-mod? I modded all my lovelace cards to be not so wide
with:
style: |
ha-card {
box-shadow: var(--card-box-shadow);
margin: 0px 8px 15px 8px;
}
with button-card the right card always gets cut off.
Ah yes, the old clip the box shadow problem. This is the best solution that I have come up with. As a side note, I have also been adding outlines in various places controlled by an input_boolean
that helps immensely in visualizing what is going on. Of course you can also use the browsers dev tools to figure this out, but drawing outlines is bit more efficient than always turning on dev tools.
Here is the code snippet that I use to mod horizontal-stack
. You can safely ignore the border if you don’t want a border around your horizontal-stack.
- type: custom:mod-card
style: |
ha-card {
{% if is_state('input_boolean.show_outlines', 'on') %} outline: 1px solid red; {% endif %}
/* --------------------------------------------------
Add space inside the border of horizontal-stack.
This adds space between the border of the horizontal-stack
and the outside of the contained elements so that
those elements don't butt up against the inside
of the horizontal-stack (and there is room for the
box-shadow
-------------------------------------------------- */
padding: 15px;
border: 2px solid black;
}
card:
type: horizontal-stack
cards:
Edit: I don’t think its so much that button-card
has weird behavior, its just understanding the underlying DOM structure and getting more familiar with CSS. button-card
has been a fantastic way to learn how this all works. The “framework” provided along with the ability to use embedded Javascript is extremely powerful. @RomRider has created something very unique here! (Thanks man!)
you come up with some crazy tricks there haha. Thanks alot! Weird behavior only for the unkown, this is so true for many things in life!
I have these button cards with color_type: card and color is displaying only once and it’s disappearing.
I would like to have the button card stay with the color as long as that entity state is on.
Am I missing anything?
UI: (dark theme - Hulu switch state is on)
UI: (light theme)
Code:
- type: custom:stack-in-card
title: Family Room TV
mode: vertical
cards:
- type: horizontal-stack
cards:
- type: custom:button-card
entity: switch.tv_activity_hulu_switch
icon: mdi:hulu
name: Hulu
color_type: card
# color: auto
# color: rgb(223, 255, 97)
color: "#7CBE6E"
- type: custom:button-card
entity: switch.tv_activity_plex_switch
icon: mdi:plex
name: Plex
color_type: card
color: "#7CBE6E"
- type: custom:button-card
entity: switch.tv_activity_hotstar_switch
icon: mdi:star
name: Hotstar
color_type: card
color: "#7CBE6E"
- type: horizontal-stack
cards:
- type: custom:button-card
entity: switch.tv_activity_cnn_switch
icon: mdi:newspaper
name: CNN
color_type: card
color: "#7CBE6E"
- type: custom:button-card
entity: switch.tv_activity_disney_switch
icon: mdi:music-circle
name: Disney
color_type: card
color: "#7CBE6E"
- type: custom:button-card
entity: remote.harmony_hub
icon: mdi:power
name: Harmony
color_type: card
# color: auto
color: "#CE2841"
With stack-in-card the background is removed unless you specify it in the keep
object. Check the documentation of stack-in-card on github you’ll see
Haha great! You really cleaned that up. Now that we don’t need extra_styles we can delete id="c_brightness"
and add r="${radius}"
to the circle.
Bingo! I was looking at ‘vertical-stack-in-card’ documentation instead of your ‘stack-in-card’.
Bugfixes
- Units would be shown even with
show_units: false
(Fix #321) - Card would not work properly with HA < 0.107 (Fix #322)
Is there a way to change the display name of a state on the button-card?
For example: My TV state is “Standby”, but I want it to say “Off” on the card.
Thanks so much!
You need to use the state display option with JavaScript.
Can someone assist with Templating tap actions?
Is it possible to do different actions based on the state?
please allow me this maintenance question, I might have missed an update to the action field:
is this:
hold_action:
action: call-service
service: automation.trigger
service_data:
entity_id: entity
still correct for firing an automation which is the entity of the button? I ask because it very often doesn’t work (could also be caused by the conditional styling of the card, which is animated: blink 2s ease infinite
which makes it a bit more difficult to touch the button on an iPhone…
reason I am expanding on this also, is I have several ‘Alert’ buttons showing on my Home view, in a conditional card, and on their own detailed view for the specific info. Example: a GitHub update is available: ping!, Home view shows the update button.
The same button also shows on my developer view, with all other stuff on the GitHub repos I use.
What I would love to do is, depending on the view I am on, have a hold-action defined.
On my Home view, I would like the hold-action to be a navigate to the developer view,
hold_action:
action: navigate
navigation_path: developer
and, on the developer view, the hold action would need to be what I posted above, trigger the automation.
hold_action:
action: call-service
service: automation.trigger
service_data:
entity_id: entity
I would hope to be able to write a template for that, but of course would need to access view
in the JS templates
@RomRider would you allow to do this please?
As I have about 12 alert buttons, for which this scenario would go, it would be amazing if we could:
a) use templates for the actions, that
b) see the view
in Jinja I would be able to write this in a service_template, or maybe even a subscript, but in JS I am not sure how to proceed, so if at all possible would need some help here too…
please have a look? thanks!
Hey there,
is it possible to display to notifications? The example
- type: custom:button-card
icon: mdi:lightbulb
aspect_ratio: 1/1
name: Nb lights on
styles:
grid:
- position: relative
custom_fields:
notification:
- background-color: >
[[[
if (states['input_number.test'].state == 0)
return "green";
return "red";
]]]
- border-radius: 50%
- position: absolute
- left: 60%
- top: 10%
- height: 20px
- width: 20px
- font-size: 8px
- line-height: 20px
custom_fields:
notification: >
[[[ return Math.floor(states['input_number.test'].state / 10) ]]]
shows one notification in the right upper corner. I would like to show another notification in the right corner at the bottom.
Is this possible?
I have the following button set up:
type: 'custom:button-card'
entity: switch.pool_pump
tap_action:
action: more-info
name: |
[[[
if (states["timer.clean_cycle"].state == 'idle') return states['sensor.pump_on_today'].state + " h";
else return "."
]]]
show_icon: true
show_name: true
custom_fields:
timer:
card:
type: entities
entities:
- timer.clean_cycle
graph: line
styles:
grid:
- position: relative
custom_fields:
timer:
- position: absolute
- overflow: unset
- top: 78%
- left: 15%
- height: 0px
It shows the state of the pool pump. There are 2 values that I would like to display as the name/label depending on what the pump is doing ie ‘Clean cycle’ or otherwise:
During the Clean cycle the ‘time remaining’ is displayed, otherwise the hours run for the day are displayed.
The only way I know to show a timer counting down in real time is by using an ‘Entities’ card. I therefore embedded it in the button using a custom-field.
Positioning the custom-field was fiddly as I’m not that familiar with CSS styling, but eventually got there. The problem is that the position of the value changes depending on the size of the button.
Any ideas on how to correct this or other ways to do it, would be most welcome.
I get that width:
and height:
are in px. But, I’m using transparent and non-transparent button-cards as overlays on picture-elements
cards to drive actions. Picture-elements
’ images scale with the size of the display, but not the custom:button-cards
laid on them. Is there a way to scale the button-card dimensions as a percent to keep them in sync with the screen-size?