-
Notifications
You must be signed in to change notification settings - Fork 168
Theme cookbook
Note: If you mix a non--yaml
chunk with a -yaml
chunk, substitute like this:
card-mod-root: |
app-toolbar {
display: none;
}
card-mod-root-yaml: |
paper-tabs$: |
.not-visible {
display: none;
}
card-mod-root-yaml: |
paper-tabs$: |
.not-visible {
display: none;
}
.: |
app-toolbar {
display: none;
}
no-top-header:
card-mod-theme: no-top-header
card-mod-root: |
app-toolbar {
display: none;
}
With only one view
With multiple views
no-header:
card-mod-theme: no-header
card-mod-root: |
app-header {
display: none;
}
transparent-header:
card-mod-theme: transparent-header
card-mod-root: |
ha-app-layout {
background: url("https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTR-Hllcy5CR5U90nMlW8bZA_VM7w4VlP2lZg&usqp=CAU");
}
app-header {
background: rgba(0,0,0,0.5) !important;
}
app-toolbar {
background: none !important;
}
Note: app-header
and app-toolbar
overlap, so if you make both of them transparent, things will look weird. Better to make one have no background.
Note2: the --lovelace-background
variable applies a background to the view, but the header is outside of the view, so you can't use that to get a background behind it - unless you also move it 🤔
tabs-to-edge:
card-mod-theme: tabs-to-edge
card-mod-root-yaml: |
paper-tabs$: |
.not-visible {
display: none;
}
battery-rows:
card-mod-theme: battery-rows
card-mod-row: |
:host {
display: block;
{% set battery = state_attr(config.entity, 'battery') or state_attr(config.entity, 'battery_level') %}
{% if battery %}
background: linear-gradient(to right, rgba(0,255,0,0.5), {{battery}}%, white {{battery}}%);
{% endif %}
}
custom-secondary:
card-mod-theme: custom-secondary
card-mod-row-yaml: |
hui-generic-entity-row$: |
{% set battery = state_attr(config.entity, 'battery') or state_attr(config.entity, 'battery_level') %}
{% if battery %}
.info.text-content::after {
content: "{{battery}}%";
display: block;
color: var(--secondary-text-color);
}
{% endif %}
.info.text-content
will select only rows that don't already have a secondary-info row.
fan-spinning:
card-mod-theme: fan-spinning
card-mod-card: |
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
ha-icon[data-domain="fan"][data-state="on"] {
animation: spin 4s infinite linear;
}
card-mod-row-yaml: |
"*:first-child$": |
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
state-badge {
{% if config.entity.startswith('fan.') and is_state(config.entity, 'on') %}
animation: spin 4s infinite linear;
{% endif %}
}
one-column:
card-mod-theme: one-column
card-mod-view: |
"hui-masonry-view$#columns" {
flex-direction: column !important;
margin: 0 auto;
max-width: 500px;
}
Card-mod themes can be used to replace much of the functionality that was previously available in the now defunct custom-header. Here are a few examples. Others are possible if you find the right CSS properties to change. Hopefully these examples serve as a starting point.
This example gets rid of the menu button on the left that shows when viewing on mobile (you can still swipe from the left to open the sidebar), and the title text.
card-mod-theme: "NAME_OF_YOUR_THEME_HERE"
card-mod-root-yaml: |
.: |
ha-menu-button {
display: none !important;
}
In Custom Header, you would have done this like (before compact mode being default behavior in v.117 of Home Assistant)
custom_header:
compact_mode: true
config:
menu_hide: true
This example changes the overflow menu with a clock while keeping the menu functional (click on the time to open the menu). You must have the time and date integration enabled with sensor.time
. In order to use position:absolute
, you will have to start with a large value for width, such as 400px and then reduce it until you get it into the correct position on the right of the screen (example shown below is for date and time). If you have something short you'd like to use instead of the menu button, you can try using position:relative
instead, which can correctly position it without the width parameter, but leaves you with a small box so only works for a small item like a clock with no date.
card-mod-theme: "NAME_OF_YOUR_THEME_HERE"
card-mod-root: |
ha-button-menu::before {
content: "{{states('sensor.time_formatted')}}";
color: var(--text-primary-color);
visibility: visible;
position: absolute;
font-size: 20px;
width: 230px;
top: 13px;
right: 0px;
}
ha-menu-button {
display: none !important;
}
ha-button-menu {
color: transparent;
}
In custom header, doing the same thing would have looked like this
button_text:
menu: 'menu'
options: '{{ dayNameShort }}, {{ dayNum }} {{ monthNameShort }} {{ hours24LZ }}:{{ minutesLZ }}'
If we want, we can also make the clock conditional to a specific user. In this example we will replace the overflow menu with a clock only for the 'kiosk' user. The template conditional statement {% if user == 'USERNAME' %}
can be used to make conditional formatting for different elements of your theme specific to the logged in user.
card-mod-theme: "NAME_OF_YOUR_THEME_HERE"
card-mod-root-yaml: |
.: |
{% if user == 'kiosk' %}
mwc-icon-button[slot="trigger"] > ha-svg-icon {
display: none;
}
mwc-icon-button[slot="trigger"]::after {
font-size: 22px;
height: 20px;
width: 100px;
margin-left: 0px;
margin-right: 0px;
content: "{{ states('sensor.time') }}";
position: absolute;
top: 14px;
right: 0px;
}
{% endif %}
This conditional styling by user is similar to the custom header config
- conditions:
user: kiosk
This example does some changes that are applied specifically to all browsers in portrait orientation. It removes the overflow menu and chevrons.
card-mod-theme: "NAME_OF_YOUR_THEME_HERE"
card-mod-root-yaml: |
.: |
ha-menu-button {
display: none !important;
}
@media (orientation: portrait) {
a.menu-link[target="_blank"], ha-button-menu, [main-title] {
display: none;
}
paper-icon-button[icon="paper-tabs:chevron-right"] {
display: none;
}
paper-icon-button[icon="paper-tabs:chevron-left"] {
display: none;
}
}
This would have been similar to (but not exactly the same as*) a custom header config of:
- conditions:
template: "{{ 'iPhone' in userAgent or 'iOS' in userAgent }}"
config:
menu_hide: true
options_hide: true
chevrons: false
*In custom header, this would check if when you loaded the page, you told the website that you're running on an iOS device. In card-mod, this just checks if your height is greater than your width (so it would trigger if you resized your desktop browser to portrait mode).
Below is an example of using many different of the custom header type features to create a header that is on the bottom of the screen with changes in colors and removing items like the title and some buttons. It might help you learn some stuff as well (but you should learn basic CSS too).
and this chunk might not be regularly updated For some reason now it's more frequently updated? Maybe more people remind me in the card-mod thread than in the other thread.
This supports uncommenting various items to do stuff like moving it to the bottom. Scream at @KTibow over there if you want more functionality.
compact-header:
card-mod-theme: compact-header
header-height: 48px
card-mod-root-yaml: |
paper-tabs$: |
/* Uncomment this for header on the bottom. You're 1/3 there.
#selectionBar {
bottom: unset !important;
}
*/
.: |
/* This moves the header up. */
app-header {
transform: translate3d(0px, -48px, 0px);
}
/* Let's change the background. */
app-header, app-toolbar {
background: var(--primary-background-color) !important;
color: var(--primary-text-color) !important;
}
/* We're still going to need a way to see that we're in edit mode. */
app-header.edit-mode {
padding-bottom: calc(var(--ha-card-border-width, 2px) * 2);
border-bottom: var(--ha-card-border-width, 2px) solid var(--primary-color);
}
/* This changes the color of the currently selected tab. */
ha-tabs {
--paper-tabs-selection-bar-color: var(--primary-color) !important;
}
paper-tab[aria-selected=true] {
color: var(--primary-color) !important;
}
/* This hides the help button. */
a.menu-link[target="_blank"] {
display: none;
}
/* This makes the plus color the same as the background. */
#add-view {
color: var(--primary-background-color);
}
/* This hides the title. */
[main-title] {
display: none;
}
/* This hides the app-toolbar in edit mode. */
app-toolbar.edit-mode {
height: 0;
}
/* This moves the edit mode buttons back in. */
app-toolbar.edit-mode > mwc-icon-button {
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
app-toolbar.edit-mode > ha-button-menu {
position: absolute;
right: 0;
top: 0;
z-index: 1;
}
/* This adds a bit more padding, mainly for unused entities. */
app-header.edit-mode > div {
padding-left: 5px;
}
/* Uncomment this for header on the bottom. You're 2/3 there.
app-header {
top: calc(100vh - 60px) !important;
bottom: 0 !important;
transform: unset !important;
}
*/
/* Uncomment this to move the main content up to fill the gap left by the shifted header. You're 3/3 there.
card-mod-view-yaml: |
.: |
hui-view {
transform: translate3d(0px, -60px, 0px);
}
*/
Other components that can replace some of custom header's functionality
Here are a few other things that can help recreate functionality from custom header.
First, version 0.117 of Home Assistant makes the compact header that made custom header famous default behavior. So if you haven't already, you should upgrade.
The hide_tabs
functionality of Custom Header is now also standard in Home Assistant with the "visibility" tab in the tab editor (or if you use YAML).
If you want to hide the header or sidebar completely, the creator of Custom Header has a Kiosk Mode plugin as well.
If you'd like to remove the mic button from your header as was done with the voice_hide: true
option in Custom Header, remove Almond from your list of configured integrations. Or if you use configuration.yaml
, remove this line:
conversation: