
Navbar Card is a custom Lovelace card designed to simplify navigation within your Home Assistant dashboard, heavily inspired by the great work of Adaptive Mushroom and Google's Material Design. It provides a sleek, responsive navigation bar that displays as a full-width bar at the bottom on mobile devices. On desktop, it adapts into a flexible container that can be positioned on any side of the screen (top, bottom, left, or right) adjusting its orientation to fit seamlessly.
Installation β’ Quickstart β’ Configuration β’ Dashboard adjustements β’ Example configurations β’ Help β’ Donate
HACS manual configuration
- Go to HACS in Home Assistant.
- On the top right, click "Custom repositories".
- Enter the repository URL: https://github.com/joseluis9595/lovelace-navbar-card.git
- Search for "Navbar Card".
- Click Install!
Manual installation without HACS
- Download navbar-card.js from the latest release.
- Move this file to home assistant's
<config>/www
folder. - In home assistant, go to
Settings > Dashboards
. - On the top right corner, click
Resources
. - Add a new resource with the following:
- URL:
/local/navbar-card.js
- Resource type: JavaScript module
- URL:
- Go to your dashboard, refresh your page and add your new navbar-card!
- Edit your Home Assistant dashboard: Go to your dashboard in Home Assistant and enter edit mode.
- Add the Navbar Card: Click to add a new card, search for "navbar-card", and add it anywhere in your dashboard layout (doesn't matter where, navbar-card will automatically float to the bottom on mobile devices, and to the position you have configured for desktop devices).
- Configure your routes: In the card configuration, define a few routes to the views you want quick access to. For example:
type: custom:navbar-card
routes:
- url: /lovelace/home
icon: mdi:home
label: Home
- url: /lovelace/lights
icon: mdi:lightbulb-outline
label: Lights
- url: /lovelace/devices
icon: mdi:devices
label: Devices
- Save and enjoy: Save your dashboard. The navbar will now appear and let you quickly switch between your configured views!

Name | Type | Default | Description |
---|---|---|---|
routes |
Routes | Required |
Defines the array of routes to be shown in the navbar |
desktop |
Desktop | - | Options specific to desktop mode |
mobile |
Mobile | - | Options specific to mobile mode |
template |
Template | - | Template name |
layout |
Layout | - | Layout configuration options |
styles |
Styles | - | Custom CSS styles for the card |
haptic |
Haptic | - | Fine tune when the haptic events should be fired in the card |
Routes represents an array of clickable icons that redirects to a given path. Each item in the array should contain the following configuration:
Name | Type | Default | Description |
---|---|---|---|
url |
string | Required* |
The path to a Lovelace view. Ignored if tap_action is defined. |
icon |
string | JSTemplate | - | Material icon to display as this entry icon. Either icon or image is required. |
icon_selected |
string | JSTemplate | - | Icon to be displayed when url matches the current browser URL |
image |
string | JSTemplate | - | URL of an image to display as this entry icon. Either icon or image is required. |
image_selected |
string | JSTemplate | - | Image to be displayed when url matches the current browser URL |
badge |
Badge | - | Badge configuration |
label |
string | JSTemplate | - | Label to be displayed under the given route if show_labels is true |
tap_action |
tap_action | - | Custom tap action configuration. |
hold_action |
hold_action | - | Custom hold action configuration. |
double_tap_action |
double_tap_action | - | Custom double_tap action configuration. |
popup |
Popup items | - | List of routes to display in a popup menu |
hidden |
boolean | JSTemplate | - | Controls whether to render this route or not |
selected |
boolean | JSTemplate | - | Controls whether to display this route as selected or not. If not defined, the selected status will be computed as route.url == window.location.pathname |
Note:
url
is required unlesstap_action
,hold_action
,double_tap_action
orpopup
is present.
Note: If
tap_action
is defined,url
is ignored.
Tip: Some suggestions when using the
image
property:
- Place your custom images in the
<ha-config-folder>/www
directory- Use images with a transparent background for best results
- Keep image dimensions squared for best results
Apart from the standard Home Assistant actions (navigate, call-service, etc.), navbar-card
supports some additional custom actions:
Action | Description | Required Parameters |
---|---|---|
open-popup |
Opens the popup menu defined in the route | None |
toggle-menu |
Opens the native HA side menu | None |
show-notifications |
Opens the native HA notifications drawer | None |
quickbar |
Opens the native HA quickbar | mode: entities | commands | devices |
navigate-back |
Navigates back to the previous page in the browser history | None |
open-edit-mode |
Opens the current dashboard in edit mode | None |
Example:
type: custom:navbar-card
...
routes:
...
- url: /lovelace/lights
icon: mdi:lightbulb-outline
tap_action:
action: open-popup # Will open the popup menu defined for this route
double_tap_action:
action: quickbar # Will open the native HA quickbar
mode: entities
hold_action:
action: toggle-menu # Will open the native HA side menu
- icon: mdi:pencil
tap_action:
action: open-edit-mode
Configuration to display a small badge on any of the navbar items.

Name | Type | Default | Description |
---|---|---|---|
show |
boolean | JSTemplate | false | Boolean template indicating whether to display the badge or not |
color |
string | JSTemplate | red | Background color of the badge |
count |
string | JSTemplate | - | Text to be displayed inside the badge |
textColor |
string | JSTemplate | - | Color for the text displayed inside the badge |
For each route, a popup menu can be configured, to display a popup when clicked. This is activated using the open-popup
action in either tap_action
or hold_action
.

Name | Type | Default | Description |
---|---|---|---|
url |
string | Required* |
The path to a Lovelace view. Ignored if tap_action is defined. |
icon |
string | JSTemplate | - | Material icon to display as this entry icon. |
icon_selected |
string | JSTemplate | - | Icon to be displayed when url matches the current browser URL |
image |
string | JSTemplate | - | URL of an image to display as this entry icon. |
image_selected |
string | JSTemplate | - | Image to be displayed when url matches the current browser URL |
badge |
Badge | - | Badge configuration |
label |
string | JSTemplate | - | Label to be displayed under the given route if show_labels is true |
tap_action |
tap_action | - | Custom tap action configuration, including 'open-popup' to display a popup menu. |
hold_action |
hold_action | - | Custom hold action configuration, including 'open-popup' to display a popup menu. |
selected |
boolean | JSTemplate | - | Controls whether to display this item as selected or not. If not defined, the selected status will be computed as item.url == window.location.pathname |
Note:
url
is required unlesstap_action
is present. Iftap_action
is defined,url
is ignored.
You can easily customize some properties of the navbar-card by writing your own JavaScript rules. To do this, you simply wrap the value of the field that supports JSTemplates in [[[
and ]]]
, then write the JavaScript code that determines the property's value.
Apart from using plain javascript, you can access some predefined variables:
states
-> Contains the global state of all entities in HomeAssistant. To get the state of a specific entity, use:states['entity_type.your_entity'].state
.user
-> Information about the current logged user.navbar
-> Internal state of the navbar-card. Accessible fields are:isDesktop
-> Boolean indicating whether the card is in its desktop variant or not.
Tip: You can use
console.log
in your JSTemplate to help debug your HomeAssistant states.
Below is an example using JSTemplates for displaying a route only for one user, and a label indicating the number of lights currently on:
type: custom:navbar-card
desktop:
position: bottom
show_labels: true
routes:
- url: /lovelace/lights
label: |
[[[
const lightsOn = Object.entries(states)
.filter(([entityId, value]) => {
return entityId.startsWith('light.') && value.state == 'on';
})
.length;
return `Lights (${lightsOn})`
]]]
icon: mdi:lightbulb-outline
icon_selected: mdi:lightbulb
hidden: |
[[[ return navbar.isDesktop; ]]]
- url: /lovelace/devices
label: Devices
icon: mdi:devices
hidden: |
[[[ return user.name != "jose"; ]]]
Specific configuration for desktop mode.

Name | Type | Default | Description |
---|---|---|---|
show_labels |
boolean | popup_only | routes_only |
false |
Whether or not to display labels under each route |
min_width |
number | 768 |
Screen size from which the navbar will be displayed as its desktop variant |
position |
top | bottom | left | right |
bottom |
Position of the navbar on desktop devices |
hidden |
boolean | JSTemplate | false |
Set to true to hide the navbar on desktop devices |
Specific configuration for mobile mode.

Name | Type | Default | Description |
---|---|---|---|
show_labels |
boolean | popup_only | routes_only |
false |
Whether or not to display labels under each route |
hidden |
boolean | JSTemplate | false |
Set to true to hide the navbar on mobile devices |
mode |
docked | floating |
docked |
Choose visualization mode on mobile devices. docked for default experience, floating for desktop-like visualization |
Controls when haptic feedback is triggered. You can either use a boolean to enable/disable all haptic feedback, or specify which actions should trigger haptic feedback:
Option | Type | Default | Description |
---|---|---|---|
url |
boolean | false |
Trigger when navigating to a new page |
tap_action |
boolean | false |
Trigger on tap actions |
hold_action |
boolean | false |
Trigger on hold actions |
double_tap_action |
boolean | false |
Trigger on double tap actions |
Templates allow you to predefine a custom configuration for navbar-card
and reuse it across multiple dashboards. This approach saves time and simplifies maintenance β any change to the template will automatically apply to all cards using it.
To define custom templates, add them under navbar-templates
in your main Lovelace YAML configuration like this:
navbar-templates:
your_template_name:
# Your navbar config
routes:
- label: Home
icon: mdi:home
url: /lovelace/home
...
# Your normal lovelace configuration
views:
...
You can reference a template from your navbar-card
using the template property:
type: custom:navbar-card
template: your_template_name
Card properties defined directly in the card will take priority over those inherited from the template.
For example, if you want to use a template called your_template_name
but have one specific dashboard with a different primary color, your configurations might look like this:
- Default Navbar for Most Views:
type: custom:navbar-card
template: your_template_name
- Customized Navbar for a Specific View:
type: custom:navbar-card
template: your_template_name
styles: |
.navbar {
--navbar-primary-color: red;
}
Configuration options for the navbar layout and behavior.
Name | Type | Default | Description |
---|---|---|---|
auto_padding |
Auto Padding | - | Add padding to your Home Asistant dashboard to prevent overlaps |
Automatically adds padding to your Home Assistnat dashboard to prevent cards from overlapping with navbar-card
. This eliminates the need for manual CSS padding adjustments in your Home Assistant theme.
Name | Type | Default | Description |
---|---|---|---|
enabled |
boolean | true |
Whether to automatically add padding to prevent overlaps |
desktop_px |
number | 100 |
Padding in pixels for desktop mode (applied to left/right based on position) |
mobile_px |
number | 80 |
Padding in pixels for mobile mode (applied to bottom) |
Note: The
desktop_px
padding is automatically applied to the appropriate side based on your navbar'sdesktop.position
setting.
Custom CSS styles can be applied to the Navbar Card to personalize its appearance and adapt it to your dashboard's design. Simply provide a CSS string targeting the relevant classes to style the navbar to your liking.
You can check out some examples here for inspiration.
Here is a breakdown of the CSS classes available for customization:
-
.navbar
: Base component for the navbar..navbar.desktop
: Styling for the desktop version..navbar.desktop.[top | bottom | left | right]
: Specific styles for different positions of the navbar..navbar.mobile
: Styling for the mobile version..navbar.mobile.floating
: Styling for the mobile version when usingfloating
mode.
-
.route
: Represents each route (or item) within the navbar. -
.button
: Background element for each icon..button.active
: Applies when a route is selected.
-
.icon
: Refers to the ha-icon component used for displaying icons..icon.active
: Applies when a route is selected.
-
.image
: Refers to the img component used for displaying route images..image.active
: Applies when a route is selected.
-
.label
: Text label displayed under the icons (if labels are enabled)..label.active
: Applies when a route is selected.
-
.badge
: Small indicator or badge that appears over the icon (if configured)..badge.active
: Applies when a route is selected.
-
.navbar-popup
: Main container for the popup. -
.navbar-popup-backdrop
: Backdrop styles for the popup. -
.popup-item
: Styles applied to the container of each popup-item. This object contains both the "button" with the icon, and the label..popup-item.label-[top | bottom | left | right]
: Specific styles for different positions of the label..popup-item .label
: Styles applied to the label of each popup item..popup-item .button
: Button for each popup item, containing just the icon.
If you're using the Navbar Card, you might notice it could collide with other cards on your dashboard. The navbar-card now includes an automatic padding feature that handles this for you, eliminating the need for manual CSS adjustments.
The navbar-card automatically adds appropriate padding to prevent overlaps:
- Desktop: Adds padding to the left or right side based on your navbar position
- Mobile: Adds bottom padding to prevent cards from overlapping the bottom navbar
This feature is enabled by default, but you can customize it using the layout.auto_padding
configuration. More info here
If you prefer to handle padding manually or need more control, you can disable automatic padding and use CSS instead:
type: custom:navbar-card
layout:
auto_padding:
enabled: false # Disable automatic padding
Then use card-mod with a custom theme to add manual padding:
your_theme:
card-mod-theme: your_theme
card-mod-root-yaml: |
.: |
/* Add padding to the left (or other sides, depending on your navbar position) for desktop screens */
@media (min-width: 768px) {
:not(.edit-mode) > #view {
padding-left: 100px !important;
}
}
/* Add bottom padding for mobile screens to prevent cards from overlapping with the navbar */
@media (max-width: 767px) {
:not(.edit-mode) > hui-view:after {
content: "";
display: block;
height: 80px;
width: 100%;
background-color: transparent;
}
}
Another useful styling detail, is removing the native ha-tabs element on the top of the screen. We want to hide the ha-tabs element, but keep the edit, search and assist buttons visible. To do so, once again, using card-mod and custom themes is quite easy:
your_theme:
app-header-background-color: transparent
app-header-text-color: var(--primary-text-color)
card-mod-theme: your_theme
card-mod-root-yaml: |
.: |
ha-tabs {
pointer-events: none;
opacity: 0;
}
your_theme:
app-header-background-color: transparent
app-header-text-color: var(--primary-text-color)
card-mod-theme: your_theme
card-mod-root-yaml: |
.: |
.toolbar > sl-tab-group {
pointer-events: none;
opacity: 0;
}
Basic example
type: custom:navbar-card
layout:
auto_padding:
enabled: true
desktop_px: 100
mobile_px: 80
desktop:
position: left
min_width: 768
show_labels: true
mobile:
show_labels: false
routes:
- icon: mdi:home-outline
icon_selected: mdi:home-assistant
url: /lovelace/home
label: Home
- icon: mdi:devices
url: /lovelace/devices
label: Devices
hold_action:
action: navigate
navigation_path: /config/devices/dashboard
- icon: mdi:thermometer
url: /lovelace/weather
label: Weather
- icon: mdi:creation-outline
icon_selected: mdi:creation
url: /lovelace/control
label: Control
- icon: mdi:dots-horizontal
label: More
tap_action:
action: open-popup
popup:
- icon: mdi:cog
url: /config/dashboard
- icon: mdi:hammer
url: /developer-tools/yaml
- icon: mdi:power
tap_action:
action: call-service
service: homeassistant.restart
service_data: {}
confirmation:
text: Are you sure you want to restart Home Assistant?
badge:
show: >
[[[ return states['binary_sensor.docker_hub_update_available'].state === 'on' ]]]
color: var(--primary-color)
Custom primary color
type: custom:navbar-card
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
styles: |
.navbar {
--navbar-primary-color: red;
}
Custom background color
type: custom:navbar-card
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
styles: |
.navbar {
background: #000000;
}
No rounded corners only in desktop mode
type: custom:navbar-card
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
styles: |
.navbar.desktop{
border-radius: 0px;
}
More spacing on desktop mode and "bottom" position
type: custom:navbar-card
desktop:
position: bottom
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
styles: |
.navbar.desktop.bottom {
bottom: 100px;
}
Custom auto-padding configuration
type: custom:navbar-card
layout:
auto_padding:
enabled: true
desktop_px: 150 # Extra wide padding for desktop
mobile_px: 120 # Extra tall padding for mobile
desktop:
position: right # Padding will be applied to the right
show_labels: true
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
Display route only for a given user
type: custom:navbar-card
desktop:
position: bottom
routes:
- url: /lovelace/home
label: Home
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
- url: /lovelace/settings
label: Settings
icon: mdi:cog
# This route will only be displayed for user "jose"
hidden: |
[[[ return user.name != "jose"]]]
Force one route to always be selected
type: custom:navbar-card
desktop:
position: bottom
routes:
- url: /lovelace/home
label: Home
selected: true # force `selected` field to true
icon: mdi:home-outline
icon_selected: mdi:home-assistant
- url: /lovelace/devices
label: Devices
icon: mdi:devices
- url: /lovelace/settings
label: Settings
icon: mdi:cog
Route with rounded user's image
type: custom:navbar-card
routes:
- image: |
[[[
return hass.states["person.jose"].attributes.entity_picture
]]]
label: More
tap_action:
action: open-popup
popup:
- icon: mdi:cog
url: /config/dashboard
- icon: mdi:hammer
url: /developer-tools/yaml
- icon: mdi:power
tap_action:
action: call-service
service: homeassistant.restart
service_data: {}
confirmation:
text: Are you sure you want to restart Home Assistant?
styles: |
.image {
border-radius: 16px !important;
}
Need help using navbar-card
, have ideas, or found a bug? Here's how you can reach out:
-
π Found a bug or have a feature request?
Open an issue on GitHub so we can track and fix it. -
π¬ Have questions, want to share feedback, or just chat?
Either start a discussion on GitHub or join the conversation on the Home Assistant Community Forum .
Your feedback helps make navbar-card better for everyone. Donβt hesitate to reach out!
If you enjoy using navbar-card
and want to support its continued development, consider buying me a coffee (or a beer πΊ), or becoming a GitHub Sponsor!
Your support means a lot and helps keep the project alive and growing. Thank you! π