mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-22 08:46:30 +00:00
Update custom cards, add custom badges and custom card features (#2258)
* Add custom card feature doc * Add layout options in custom card documentation * Update example * Add custom badge documentation * Update docs/frontend/custom-ui/custom-card.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-card.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-card-feature.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-card.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-badge.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-badge.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-badge.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-card-feature.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update docs/frontend/custom-ui/custom-card-feature.md * Apply suggestions from code review --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
117ffb7c80
commit
a34195da26
131
docs/frontend/custom-ui/custom-badge.md
Normal file
131
docs/frontend/custom-ui/custom-badge.md
Normal file
@ -0,0 +1,131 @@
|
||||
---
|
||||
title: "Custom badge"
|
||||
---
|
||||
|
||||
[Badges](https://www.home-assistant.io/dashboards/badges/) are small widgets that sit at the top of a view, above all cards. We offer a built-in badge, the [entity badge](https://next.home-assistant.io/dashboards/badges/#entity-badge), but you're not just limited that one. You can build and use your own!
|
||||
|
||||
## Defining your badge
|
||||
|
||||
Defining a badge is done in a very similar way to defining a [custom card](/docs/frontend/custom-ui/custom-card).
|
||||
|
||||
Let's create a basic badge that displays custom text at the top of the screen.
|
||||
Create a new file in your Home Assistant config dir as `<config>/www/text-badge.js` and put in the following contents:
|
||||
|
||||
```js
|
||||
|
||||
class TextBadge extends HTMLElement {
|
||||
// Whenever the state changes, a new `hass` object is set. Use this to
|
||||
// update your content.
|
||||
set hass(hass) {
|
||||
this._hass = hass;
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
// The user supplied configuration. Throw an exception and Home Assistant
|
||||
// will render an error badge.
|
||||
setConfig(config) {
|
||||
if (!config.entity) {
|
||||
throw new Error("You need to define an entity");
|
||||
}
|
||||
this.config = config;
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
updateContent() {
|
||||
if (!this.config || !this._hass) return;
|
||||
|
||||
const entityId = this.config.entity;
|
||||
const state = this._hass.states[entityId];
|
||||
const stateStr = state ? state.state : "unavailable";
|
||||
|
||||
this.innerHTML = `<p>${stateStr}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("text-badge", TextBadge);
|
||||
```
|
||||
|
||||
## Referencing your new badge
|
||||
|
||||
In our example badge, we defined a badge with the tag `text-badge` (see last line), so our badge type will be `custom:text-badge`. And because you created the file in your `<config>/www` directory, it will be accessible in your browser via the url `/local/` (if you have recently added the www folder you will need to re-start Home Assistant for files to be picked up).
|
||||
|
||||
Add a resource to your dashboard configuration with URL `/local/text-badge.js` and type `module` ([resource docs](/docs/frontend/custom-ui/registering-resources)).
|
||||
|
||||
You can then use your badge in your dashboard configuration:
|
||||
|
||||
```yaml
|
||||
# Example dashboard configuration
|
||||
views:
|
||||
- name: Example
|
||||
badges:
|
||||
- type: "custom:text-badge"
|
||||
entity: light.bedside_lamp
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Custom badges are defined as a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements). It's up to you to decide how to render your DOM inside your element. You can use Polymer, Angular, Preact or any other popular framework (except for React – [more info on React here](https://custom-elements-everywhere.com/#react)).
|
||||
|
||||
Home Assistant will call `setConfig(config)` when the configuration changes (rare). If you throw an exception if the configuration is invalid, Home Assistant will render an error badge to notify the user.
|
||||
|
||||
Home Assistant will set [the `hass` property](/docs/frontend/data/) when the state of Home Assistant changes (frequent). Whenever the state changes, the component will have to update itself to represent the latest state.
|
||||
|
||||
## Graphical badge configuration
|
||||
|
||||
Your badge can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the badge editor in the dashboard.
|
||||
|
||||
Your badge can also define a `getStubConfig` method that returns a default badge configuration (without the `type:` parameter) in json form for use by the badge type picker in the dashboard.
|
||||
|
||||
Home Assistant will call the `setConfig` method of the config element on setup.
|
||||
Home Assistant will update the `hass` property of the config element on state changes, and the `lovelace` element, which contains information about the dashboard configuration.
|
||||
|
||||
Changes to the configuration are communicated back to the dashboard by dispatching a `config-changed` event with the new configuration in its detail.
|
||||
|
||||
To have your badge displayed in the badge picker dialog in the dashboard, add an object describing it to the array `window.customBadges`. Required properties of the object are `type` and `name` (see example below).
|
||||
|
||||
```js
|
||||
import "./text-badge-editor.js";
|
||||
|
||||
class TextBadge extends HTMLElement {
|
||||
|
||||
...
|
||||
|
||||
static getConfigElement() {
|
||||
return document.createElement("text-badge-editor");
|
||||
}
|
||||
|
||||
static getStubConfig() {
|
||||
return { entity: "sun.sun" };
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("text-badge", TextBadge);
|
||||
```
|
||||
|
||||
```js
|
||||
class TextBadgeEditor extends HTMLElement {
|
||||
setConfig(config) {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
configChanged(newConfig) {
|
||||
const event = new Event("config-changed", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
});
|
||||
event.detail = { config: newConfig };
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("text-badge-editor", TextBadgeEditor);
|
||||
window.customBadges = window.customBadges || [];
|
||||
window.customBadges.push({
|
||||
type: "text-badge",
|
||||
name: "Text badge",
|
||||
preview: false, // Optional - defaults to false
|
||||
description: "A custom badge made by me!", // Optional
|
||||
documentationURL:
|
||||
"https://developers.home-assistant.io/docs/frontend/custom-ui/custom-badge", // Adds a help link in the frontend badge editor
|
||||
});
|
||||
```
|
116
docs/frontend/custom-ui/custom-card-feature.md
Normal file
116
docs/frontend/custom-ui/custom-card-feature.md
Normal file
@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "Custom card feature"
|
||||
---
|
||||
|
||||
Some dashboard cards have support for [features](https://www.home-assistant.io/dashboards/features/). These widgets add quick controls to the card. We offer a lot of built-in features, but you're not just limited to the ones that we decided to include in Home Assistant. You can build and use your own in the same way as defining [custom cards](/docs/frontend/custom-ui/custom-card).
|
||||
|
||||
## Defining your card feature
|
||||
|
||||
Below is an example of a custom card feature for [button entity](/docs/core/entity/button/).
|
||||
|
||||

|
||||
|
||||
```js
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
} from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module";
|
||||
|
||||
const supportsButtonPressCardFeature = (stateObj) => {
|
||||
const domain = stateObj.entity_id.split(".")[0];
|
||||
return domain === "button";
|
||||
};
|
||||
|
||||
class ButtonPressCardFeature extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: undefined,
|
||||
config: undefined,
|
||||
stateObj: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static getStubConfig() {
|
||||
return {
|
||||
type: "custom:button-press-card-feature",
|
||||
label: "Press",
|
||||
};
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
_press(ev) {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("button", "press", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (
|
||||
!this.config ||
|
||||
!this.hass ||
|
||||
!this.stateObj ||
|
||||
!supportsButtonPressCardFeature(this.stateObj)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return html`
|
||||
<button class="button" @click=${this._press}>
|
||||
${this.config.label || "Press"}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.button {
|
||||
display: block;
|
||||
height: var(--feature-height, 42px);
|
||||
width: 100%;
|
||||
border-radius: var(--feature-border-radius, 12px);
|
||||
border: none;
|
||||
background-color: #eeeeee;
|
||||
cursor: pointer;
|
||||
transition: background-color 180ms ease-in-out;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.button:focus {
|
||||
background-color: #cdcdcd;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("button-press-card-feature", ButtonPressCardFeature);
|
||||
|
||||
window.customCardFeatures = window.customCardFeatures || [];
|
||||
window.customCardFeatures.push({
|
||||
type: "button-press-card-feature",
|
||||
name: "Button press",
|
||||
supported: supportsButtonPressCardFeature, // Optional
|
||||
configurable: true, // Optional - defaults to false
|
||||
});
|
||||
```
|
||||
|
||||
If you want your feature to better integrate with the default design of home assistant, you can use these CSS variables:
|
||||
|
||||
- `--feature-height`: Recommended height (42px).
|
||||
- `--feature-border-radius`: Recommended border radius (12px). It be can useful to set button or slider border radius.
|
||||
- `--feature-button-spacing`: Recommended space between buttons (12px). It can be useful if you have multiple buttons in your feature.
|
||||
|
||||
The main difference with custom cards is the graphical configuration option.
|
||||
To have it displayed in the card editor, you must add an object describing it to the array `window.customCardFeatures`.
|
||||
|
||||
Required properties of the object are `type` and `name`. It is recommended to define the `supported` option with a function, so the editor can only propose the feature if it is compatible with the selected entity in the card. Set `configurable` to `true` if your entity has additional configuration (e.g. `label` option in the example above) so the editor.
|
||||
|
||||
Also, the static functions `getConfigElement` and `getStubConfig` work the same as with normal custom cards.
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Custom cards"
|
||||
title: "Custom card"
|
||||
---
|
||||
|
||||
[Dashboards](https://www.home-assistant.io/dashboards/) are our approach to defining your user interface for Home Assistant. We offer a lot of built-in cards, but you're not just limited to the ones that we decided to include in Home Assistant. You can build and use your own!
|
||||
@ -46,10 +46,20 @@ class ContentCardExample extends HTMLElement {
|
||||
}
|
||||
|
||||
// The height of your card. Home Assistant uses this to automatically
|
||||
// distribute all cards over the available columns.
|
||||
// distribute all cards over the available columns in masonry view
|
||||
getCardSize() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
// The rules for your card for sizing your card if the grid in section view
|
||||
getLayoutOptions() {
|
||||
return {
|
||||
grid_rows: 3,
|
||||
grid_columns: 2,
|
||||
grid_min_rows: 3,
|
||||
grid_max_rows: 3,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("content-card-example", ContentCardExample);
|
||||
@ -76,11 +86,15 @@ views:
|
||||
|
||||
Custom cards are defined as a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements). It's up to you to decide how to render your DOM inside your element. You can use Polymer, Angular, Preact or any other popular framework (except for React – [more info on React here](https://custom-elements-everywhere.com/#react)).
|
||||
|
||||
### Configuration
|
||||
|
||||
Home Assistant will call `setConfig(config)` when the configuration changes (rare). If you throw an exception if the configuration is invalid, Home Assistant will render an error card to notify the user.
|
||||
|
||||
Home Assistant will set [the `hass` property](/docs/frontend/data/) when the state of Home Assistant changes (frequent). Whenever the state changes, the component will have to update itself to represent the latest state.
|
||||
|
||||
Your card can define a `getCardSize` method that returns the size of your card as a number or a promise that will resolve to a number. A height of 1 is equivalent to 50 pixels. This will help Home Assistant distribute the cards evenly over the columns. A card size of `1` will be assumed if the method is not defined.
|
||||
### Sizing in masonry view
|
||||
|
||||
Your card can define a `getCardSize` method that returns the size of your card as a number or a promise that will resolve to a number. A height of 1 is equivalent to 50 pixels. This will help Home Assistant distribute the cards evenly over the columns in the [masonry view](https://www.home-assistant.io/dashboards/masonry/). A card size of `1` will be assumed if the method is not defined.
|
||||
|
||||
Since some elements can be lazy loaded, if you want to get the card size of another element, you should first check it is defined.
|
||||
|
||||
@ -90,7 +104,39 @@ return customElements
|
||||
.then(() => element.getCardSize());
|
||||
```
|
||||
|
||||
Your card can define a `getConfigElement` method that returns a custom element for editing the user configuration. Home Assistant will display this element in the card editor in the dashboard.
|
||||
### Sizing in sections view
|
||||
|
||||
You card can define a `getLayoutOptions` method that returns the min, max and default number of cells your card will take in the grid if your card is used if the [sections view](https://www.home-assistant.io/dashboards/masonry/)
|
||||
If you don't define this method, the card will take 4 columns (full width) and will ignore the rows of the grid.
|
||||
|
||||
A cell of the grid is defined with the following dimension:
|
||||
|
||||
- width: between `80px` and `120px` depending on the screen size
|
||||
- height: `56px`
|
||||
- gap between cells: `8px`
|
||||
|
||||
The different layout options are:
|
||||
|
||||
- `grid_rows`: Default number of rows the card takes
|
||||
- `grid_min_rows`: Minimal number of rows the card takes
|
||||
- `grid_max_rows`: Maximal number of rows the card takes
|
||||
- `grid_columns`: Default number of columns the card takes
|
||||
- `grid_min_columns`: Minimal number of columns the card takes
|
||||
- `grid_max_columns`: Maximal number of columns the card takes
|
||||
|
||||
Example of implementation:
|
||||
|
||||
```js
|
||||
public getLayoutOptions() {
|
||||
return {
|
||||
grid_rows: 2,
|
||||
grid_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the card will take 2 x 2 cells by default. The height of the card cannot be smaller than 2 rows. According to the cell dimension, the card will have a height of `120px` (`2` * `56px` + `8px`).
|
||||
|
||||
## Advanced example
|
||||
|
||||
@ -267,121 +313,7 @@ window.customCards.push({
|
||||
name: "Content Card",
|
||||
preview: false, // Optional - defaults to false
|
||||
description: "A custom card made by me!", // Optional
|
||||
documentationURL: "https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card/", // Adds a help link in the frontend card editor
|
||||
documentationURL:
|
||||
"https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card", // Adds a help link in the frontend card editor
|
||||
});
|
||||
```
|
||||
|
||||
## Tile features
|
||||
|
||||
The tile card has support for "features" to add quick actions to control the entity. We offer some built-in features, but you can build and use your own using similar way than defining custom cards.
|
||||
|
||||
Below is an example of a custom tile feature for [button entity](/docs/core/entity/button/).
|
||||
|
||||

|
||||
|
||||
```js
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
} from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module";
|
||||
|
||||
const supportsButtonPressTileFeature = (stateObj) => {
|
||||
const domain = stateObj.entity_id.split(".")[0];
|
||||
return domain === "button";
|
||||
};
|
||||
|
||||
class ButtonPressTileFeature extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: undefined,
|
||||
config: undefined,
|
||||
stateObj: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static getStubConfig() {
|
||||
return {
|
||||
type: "custom:button-press-tile-feature",
|
||||
label: "Press",
|
||||
};
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
_press(ev) {
|
||||
ev.stopPropagation();
|
||||
this.hass.callService("button", "press", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (
|
||||
!this.config ||
|
||||
!this.hass ||
|
||||
!this.stateObj ||
|
||||
!supportsButtonPressTileFeature(this.stateObj)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="container">
|
||||
<button class="button" @click=${this._press}>
|
||||
${this.config.label || "Press"}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0 12px 12px 12px;
|
||||
width: auto;
|
||||
}
|
||||
.button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
background-color: #eeeeee;
|
||||
cursor: pointer;
|
||||
transition: background-color 180ms ease-in-out;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.button:focus {
|
||||
background-color: #cdcdcd;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("button-press-tile-feature", ButtonPressTileFeature);
|
||||
|
||||
window.customTileFeatures = window.customTileFeatures || [];
|
||||
window.customTileFeatures.push({
|
||||
type: "button-press-tile-feature",
|
||||
name: "Button press",
|
||||
supported: supportsButtonPressTileFeature, // Optional
|
||||
configurable: true, // Optional - defaults to false
|
||||
});
|
||||
```
|
||||
|
||||
The only difference with custom cards is the graphical configuration option.
|
||||
To have it displayed in the tile card editor, you must add an object describing it to the array `window.customTileFeatures`.
|
||||
|
||||
Required properties of the object are `type` and `name`. It is recommended to define the `supported` option with a function so the editor can only propose the feature if it is compatible with the selected entity in the tile card. Set `configurable` to `true` if your entity has additional configuration (e.g. `label` option in the example above) so the editor.
|
||||
|
||||
Also, the static functions `getConfigElement` and `getStubConfig` work the same as with normal custom maps.
|
||||
|
@ -40,6 +40,8 @@ module.exports = {
|
||||
label: "Custom UI",
|
||||
items: [
|
||||
"frontend/custom-ui/custom-card",
|
||||
"frontend/custom-ui/custom-card-feature",
|
||||
"frontend/custom-ui/custom-badge",
|
||||
"frontend/custom-ui/custom-strategy",
|
||||
"frontend/custom-ui/custom-view",
|
||||
"frontend/custom-ui/creating-custom-panels",
|
||||
@ -287,7 +289,7 @@ module.exports = {
|
||||
"asyncio_categorizing_functions",
|
||||
"asyncio_working_with_async",
|
||||
"asyncio_thread_safety",
|
||||
"asyncio_blocking_operations"
|
||||
"asyncio_blocking_operations",
|
||||
],
|
||||
},
|
||||
],
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Loading…
x
Reference in New Issue
Block a user