Custom strategies
Introduced in Home Assistant 2021.5.
Strategies are custom elements that generate custom dashboards and/or views. You can create new strategies in the frontend repository, or create custom strategies loaded as dashboard resources. Both have access to the Home Assistant API similar to custom cards.
A strategy can generate a single view, or a full dashboard including one or several views.
As with custom cards, custom strategies need to be loaded as resources. Refer to registering resources for more information on how to include strategies as resources.
If you have already built a custom card, the setup will feel familiar. Strategies are loaded the same way, but instead of rendering a single card directly they generate dashboard content. They can also work alongside custom cards when you need them to. You can import custom cards into your strategy as with any other resource/element.
Dashboards
A dashboard strategy generates a full dashboard configuration. In most cases, it starts from a small strategy config and returns the full dashboard structure. Think of this like a json/yaml config which is then rendered into a dashboard. Built in dashboards are built with dashboard strategies. You can read the source code for the built in dashboards here.
Show your community dashboard in the new dashboard dialog
Introduced in Home Assistant 2026.5.
If you already have a dashboard strategy, you can make it much easier for people to add by registering your strategy in window.customStrategies.
Once the resource is loaded, Home Assistant can show your dashboard in the new dashboard dialog under the Community dashboards section.
The object supports the following keys:
| Key | Required | Description |
|---|---|---|
type | Yes | The strategy type without the custom: prefix. |
strategyType | Yes | Set to "dashboard" to register a dashboard strategy. |
name | No | Friendly name shown in the picker. |
description | No | Short text shown below the name. |
documentationURL | No | Link to your documentation. This is not shown in the strategy UI yet. |
Example:
window.customStrategies = window.customStrategies || [];
window.customStrategies.push({
type: "my-demo",
strategyType: "dashboard",
name: "My demo dashboard",
description: "A starter dashboard generated from JavaScript.",
documentationURL: "https://example.com/my-demo-dashboard",
});
Suggest values in the create dialog
Dashboard strategies can also suggest initial values for the dashboard details form that opens after a user picks the strategy.
To do this, add a static getCreateSuggestions(hass) method to your dashboard strategy element. Return an object with any of these optional keys:
| Key | Description |
|---|---|
title | Suggested dashboard title. |
icon | Suggested dashboard icon, like mdi:home. |
Example:
class MyDemoDashboardStrategy extends HTMLElement {
static getCreateSuggestions(_hass) {
return {
title: "My demo dashboard",
icon: "mdi:view-dashboard",
};
}
static async generate(config, hass) {
// ...
}
}
These values are only defaults for the dialog. Users can still change them before creating the dashboard.
Examples
A good example to start from is the home overview dashboard or the energy dashboard.
Or, for a less complex example, the map dashboard strategy which imports the map view strategy. This in turn uses a panel view type, which uses a single map card.
Basic example
This example is meant to be copied into a JavaScript file and loaded as a module resource. It includes both the strategy registration and the metadata needed to show it in the new dashboard dialog.
It is a good starting point, but we recommend using Lit's ReactiveElement instead of HTMLElement and using types either with TypeScript or JSDoc. See the frontend repo for full code examples.
class MyDemoDashboardStrategy extends HTMLElement {
static getCreateSuggestions(_hass) {
return {
title: "My demo dashboard",
icon: "mdi:view-dashboard",
};
}
static async generate(config, hass) {
const title = config.title || "My demo dashboard";
const locationName = hass.config.location_name || "Home Assistant";
return {
title,
views: [
{
title: "Home",
path: "home",
cards: [
{
type: "markdown",
content:
`# ${locationName}\n\n` +
"This dashboard was generated by a community dashboard strategy.",
},
{
type: "entities",
entities: ["sun.sun"],
},
],
},
],
};
}
}
customElements.define("ll-strategy-dashboard-my-demo", MyDemoDashboardStrategy);
window.customStrategies = window.customStrategies || [];
window.customStrategies.push({
type: "my-demo",
strategyType: "dashboard",
name: "My demo dashboard",
description: "A small starter dashboard generated from JavaScript.",
documentationURL:
"https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy",
});
Use the following dashboard configuration to use this strategy:
strategy:
type: custom:my-demo
Views
A view strategy generates the configuration of a specific dashboard view. These can be reused in dashboard strategies if needed, as can custom cards be used in view strategies.
This section is about view strategies. If you want to build a custom view layout element instead, refer to custom views.
Use the following dashboard configuration to use this strategy:
views:
- strategy:
type: custom:my-demo
title: Generated view
Full strategy example
It is often a good idea to let a dashboard strategy create the list of views, and let a view strategy generate the cards for each view. That keeps the first dashboard load smaller and lets Home Assistant build each view only when it is opened.
The example below creates one view per area. Each generated view shows the entities for that area in a grid.
class MyAreaDashboardStrategy extends HTMLElement {
static getCreateSuggestions(_hass) {
return {
title: "Area dashboard",
icon: "mdi:floor-plan",
};
}
static async generate(config, hass) {
// Query all the data we need. We will make it available to views by storing it in strategy options.
const [areas, devices, entities] = await Promise.all([
hass.callWS({ type: "config/area_registry/list" }),
hass.callWS({ type: "config/device_registry/list" }),
hass.callWS({ type: "config/entity_registry/list" }),
]);
return {
title: config.title || "Area dashboard",
views: areas.map((area) => ({
title: area.name,
path: area.area_id,
strategy: {
type: "custom:my-area-dashboard",
area: area,
devices: devices,
entities: entities,
},
})),
};
}
}
class MyAreaViewStrategy extends HTMLElement {
static async generate(config, hass) {
const areaDevices = new Set();
// Find all devices in this area.
for (const device of config.devices) {
if (device.area_id === config.area.area_id) {
areaDevices.add(device.id);
}
}
const cards = [];
// Find all entities in this area or belonging to a device in this area.
for (const entity of config.entities) {
if (
entity.area_id === config.area.area_id ||
(!entity.area_id && areaDevices.has(entity.device_id))
) {
cards.push({
type: "button",
entity: entity.entity_id,
});
}
}
return {
cards: [
{
type: "grid",
cards,
},
],
};
}
}
customElements.define(
"ll-strategy-dashboard-my-area-dashboard",
MyAreaDashboardStrategy,
);
customElements.define(
"ll-strategy-view-my-area-dashboard",
MyAreaViewStrategy,
);
window.customStrategies = window.customStrategies || [];
window.customStrategies.push({
type: "my-area-dashboard",
strategyType: "dashboard",
name: "Area dashboard",
description: "Build one view per area from the Home Assistant registries.",
documentationURL:
"https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy",
});
Use the following dashboard configuration to use this strategy:
strategy:
type: custom:my-area-dashboard