Repository navigation
Repeat Reference
Every key that makes a template repeat, and everything each copy is given, one row each. This page is for looking something up. For how to use them, with longer examples, see Repeating a Template (a card per item), Repeating Sections and Badges (a section, badge or view per item) and List Entries (an entry per item inside a card's own list).
On this page: Sources · Patterns · Filters · Which filters each source reads · Leaving things out · Order and how many · What each copy is given · Which value wins · Keys on the card · Strategies · List entries · When nothing comes out
| Key | What it does | Example |
|---|---|---|
for_each |
A copy per item of a list you write out. An item is a mapping of values, and a single mapping counts as a list of one | for_each: [{light: light.kitchen_ceiling}, {light: light.hall}] |
for_each_from (v1.1.0+)
|
A copy per thing Home Assistant knows about: entities, areas, devices, floors, labels, the dashboard's views, or a list a Jinja template works out | for_each_from: {domain: light, area: Kitchen} |
When both are set, for_each wins. Both work on a custom:decluttering-card-plus card (the
template has to build a card), in a view or dashboard strategy, and inside a card's own
lists through repeat:.
type: custom:decluttering-card-plus
template: light_tile
columns: 3
for_each_from:
domain: light
area: Kitchen
sort: nameA for_each_from needs one of these, or one of the filters on its own (any but
include_hidden and entity_category, which only widen a sweep), which then sweeps
entities. With none of them it is not a repeat at all, and the card is built once: sort,
limit, group_by, include_hidden, entity_category and the other shaping keys do not
count.
| Key | Repeats over | Example |
|---|---|---|
entities (v1.1.0+)
|
Entities, by id pattern. true means all of them. This is the source when no other is given. An id written out in full is kept even when hidden (v2.0.0+), and one Home Assistant has a state for but no registry entry (sun.sun) is added after the rest |
entities: 'sensor.*_temperature' |
areas (v1.1.0+)
|
Areas, by id or name | areas: true |
devices (v1.8.0+)
|
Devices, by id or name (the name you gave it, if you renamed it) | devices: 'Hue *' |
floors (v1.8.0+)
|
Floors, by id or name | floors: true |
labels (v1.8.0+)
|
Labels, by id or name. Every label in the registry gets a copy, even one nothing carries | labels: 'room_*' |
views (v2.0.0+)
|
The views of the dashboard the card is on, by title or path, in the dashboard's order | views: true |
subviews (v2.0.0+)
|
With views: include subviews, which are left out otherwise |
subviews: true |
template (v2.0.0+)
|
The list a Jinja template renders, worked out once when the card is built | template: "{{ states.light | selectattr('state','eq','on') | map(attribute='entity_id') | list }}" |
range (v1.2.0+)
|
A fixed number of copies, at most 1000. Only the position values and total are given, and no shaping key applies |
range: 5 |
Any value here can hold placeholders (v2.4.0+), filled in from the card's variables
before anything is looked up: for_each_from: {area: '[[room]]'}. The same goes for a
source a repeat: reads. See
Filters built from the card's variables.
If more than one source is written, one is used, in this order: range, template,
views, areas, devices, floors, labels, then entities.
A template: source's list can hold entity ids (each copy gets the entity values),
mappings (each copy gets the mapping's keys) or anything else (each copy gets item). Until
Home Assistant answers, the card shows nothing; a result that is not a list repeats nothing
and says why in the browser console.
More: Repeating over what Home Assistant knows.
Every source and filter takes a single pattern, a list of them (any may match), or true
for everything.
-
*is the only wildcard, and matches any run of characters, none included:sensor.*_temperature,*kitchen*. - The whole id or name has to match, not part of it:
kitchenmatches the area Kitchen, not Kitchen Island. Writekitchen*for both. - Case does not matter.
- Nothing else is special. There is no
?, no[abc], no regular expression:light.a+bmatches onlylight.a+b. -
unit:is the exception: it is compared exactly, case included, with no wildcard.unit: kWhdoes not matchkwh.
What a pattern is compared with:
| Key | Compared with |
|---|---|
entities |
the entity id (not its name) |
areas, area
|
the area's id or its name |
devices |
the device's id, or its name: the one you gave it if you renamed it, otherwise the original |
floors, floor
|
the floor's id or its name |
labels, label
|
the label's id or its name |
views |
the view's title or its path |
domain |
the part of the entity id before the dot |
device_class |
the entity's device class |
integration |
the integration that provides it (hue, mqtt, template…) |
state_class |
the entity's state class |
category |
the category's id or its name |
These narrow an entity sweep. Every filter given has to match.
| Key | Keeps | Example |
|---|---|---|
domain (v1.1.0+)
|
Entities of these domains | domain: [light, switch] |
area (v1.1.0+)
|
Entities in these areas: the entity's own area, or its device's when it has none | area: Kitchen |
floor (v1.1.0+)
|
Entities on these floors | floor: Ground floor |
label (v1.1.0+)
|
Entities carrying these labels, on the entity or on its device. An area's labels do not count for what is in it | label: night_lights |
device_class (v1.2.0+)
|
Entities reporting these device classes | device_class: [door, window] |
integration (v1.2.0+)
|
Entities from these integrations | integration: hue |
unit (v2.0.0+)
|
Entities whose state reports this unit, exactly | unit: '°C' |
state_class (v2.0.0+)
|
Entities with these state classes | state_class: total_increasing |
category (v2.0.0+)
|
Entities filed under these categories. Each copy also gets category, the name it matched |
category: Heating |
include_hidden (v2.0.0+)
|
Hidden entities too, which a sweep leaves out | include_hidden: true |
entity_category (v2.0.0+)
|
diagnostic or config entities too (or all, or true), which a sweep leaves out. Adds to the sweep rather than narrowing it |
entity_category: diagnostic |
exclude (v1.2.0+)
|
Everything except these. See below | exclude: sensor.fridge_* |
include_hidden and entity_category apply to the sweep they are written in. Under an
area, device, floor or label source, write them inside with:, since that is where the
entities are gathered.
A filter a source does not read is ignored without a warning, so check here before wondering why a filter did nothing.
| Source | Reads |
|---|---|
| entities | every filter above, plus group_by
|
areas |
area, floor, label (the area's own labels), exclude, with
|
devices |
area (the device's area), floor, label (the device's labels), exclude as patterns, with
|
floors |
exclude as patterns, with
|
labels |
exclude as patterns, with
|
views |
subviews, exclude as patterns (titles or paths) |
template |
for a list of entity ids: the entity filters and exclude. Otherwise none |
range |
none, and no shaping either |
So {devices: true, domain: light} lists every device, and the way to get "devices that
have a light" is {devices: true, with: {domain: light}}, which drops the devices with
nothing gathered.
(v1.2.0+)
| Written as | Leaves out | Example |
|---|---|---|
| a pattern, or a list | For entities: these entity ids. For areas, devices, floors and labels: these ids or names. For views: these titles or paths | exclude: [sensor.fridge_*, sensor.freezer_*] |
| a mapping | For entity and area sources: anything matching every filter in it | exclude: {area: Garage, domain: sensor} |
A mapping is one test, not a list of them: {area: Garage, domain: sensor} leaves out the
sensors in the garage, and keeps the garage's lights and every other room's sensors. To leave
out two unrelated things, use two repeats or a pattern list. Other sources read only
entities from a mapping. What is excluded always wins over what is included.
These run in this order: overrides, require, sort, reverse, then offset and
limit. range ignores all of them.
| Key | What it does | Example |
|---|---|---|
sort (v1.2.0+)
|
Orders the copies. name (the default, except for views and template, which keep their own order), entity or id, area, domain, or floor (for area copies; entity copies have no floor to sort by). Any other word sorts by that value of the copies (v1.3.0+), numbers in number order (decimals and negatives too, v2.4.0+): entity_count, level. attr:<name> sorts by a state attribute (v1.5.0+). A leading - reverses one key, and a list breaks ties (v1.5.0+). none keeps Home Assistant's order (v1.3.0+)
|
sort: [-attr:current_temperature, name] |
reverse (v1.2.0+)
|
Turns the whole order round | reverse: true |
limit (v1.2.0+)
|
At most this many copies | limit: 6 |
offset (v1.5.0+)
|
Skips this many first, so two cards can split one list | offset: 6 |
require (v1.5.0+)
|
Drops a copy whose named values are empty. A name the copies never carry drops them all | require: area |
overrides (v1.5.0+)
|
Extra values for particular copies, keyed by a pattern matched against what the copy is: an entity's id, an area's id or name, a device's, floor's or label's id or name (v2.4.0+), a group_by group (v2.4.0+), a view's path or title (v2.0.0+), or a template: copy's item (v2.0.0+). range copies cannot be targeted |
overrides: {light.kitchen_*: {colour: amber}} |
group_by (v1.8.0+)
|
Entity sweeps only: one copy per domain, area, floor or label instead of per entity. Any other word gives no copies. An entity with no value for it is left out; with label, an entity is in every group it carries |
group_by: area |
with (v1.2.0+; devices, floors, labels v1.8.0+)
|
For an area, device, floor or label source: the entities to gather for each copy, as a set of filters. Copies with nothing gathered are dropped unless keep_empty: true. Gathered entities are always in name order |
with: {domain: light} |
sort, limit and the like inside with: are ignored; they apply to the copies, not to
what each one gathers.
Values read for sorting (a name, an attribute) are read when the card builds. The card builds again when entities, devices, areas, floors, labels or categories change, not on every state change.
These are the values a copy's placeholders can use, on top of the card's own variables:.
Everything Home Assistant supplies is plain text, never read as a placeholder.
| Name | Given by | Is |
|---|---|---|
index (v1.1.0+)
|
every repeat | the copy's position, from 1 |
count (v1.1.0+)
|
every repeat | how many copies were built |
index0, first, last (v1.2.0+)
|
every repeat | the position from 0, and whether this is the first or last copy |
total (v1.2.0+)
|
for_each_from |
how many matched, before limit and offset
|
entity, name, domain, area, area_id
|
an entity source | the entity id, its name, its domain, its area's name and id (empty when it has none). There is no floor
|
category (v2.0.0+)
|
a source narrowed by category
|
the category's name |
area_id, area, area_icon, floor
|
areas |
the area's id, name, icon (empty when unset) and its floor's name |
device_id, device, name, area, area_id, manufacturer, model (v1.8.0+)
|
devices |
the device, its name (twice), where it is and what it is |
floor_id, floor, name, level (v1.8.0+)
|
floors |
the floor, its name (twice) and its level (empty when unset) |
label_id, label, name (v1.8.0+)
|
labels |
the label and its name (twice) |
items, entities, entity_count (v1.2.0+)
|
areas, devices, floors or labels with with
|
what was gathered: items is a list of entity copies (entity, name…), entities the ids, entity_count how many |
group, name, items, entities, entity_count (v1.8.0+)
|
group_by |
the group's value, its name, and what fell into it |
name, path, navigation_path, icon, view_index (v2.0.0+)
|
views |
the view, a link to it, its icon, and its position among all the views from 0 |
the mapping's keys, or item (v2.0.0+)
|
template |
what the template listed; a list of entity ids gives the entity values instead |
| the item's keys | for_each |
whatever each item holds |
count and total differ when limit or offset cuts the list, and when a template's
required: true declaration drops copies
with nothing for that variable: total is what matched, count is what was built.
# Each area, with how many lights are in it
for_each_from:
areas: true
with:
domain: light
# the template can use [[area]], [[area_id]], [[area_icon]], [[floor]],
# [[items]], [[entities]], [[entity_count]], [[index]], [[count]], [[total]]…For each copy, first wins:
- the template's
let:and anydecluttering_let(see Which value wins); - the copy's own values, with its
overrides; - the card's
variables:; - the position values (
index,count…); - the defaults, as for any card.
So a value on the card fills in what a copy does not carry, but cannot change what it does:
variables: [{name: Lamp}] on a card repeating over lights leaves every copy its own
name. Use overrides to change particular copies, or a different variable name.
In a strategy the order is the item, then the entry's variables, then the strategy's
variables, then the position values.
Beside for_each or for_each_from on a custom:decluttering-card-plus card.
| Key | What it does | Example |
|---|---|---|
columns |
How many copies side by side. Defaults to 1, a stack | columns: 3 |
min_column_width (v1.1.0+)
|
Pixels. Drops a column rather than letting copies get narrower | min_column_width: 160 |
gap (v1.2.0+)
|
Pixels between copies. Leave it out for Home Assistant's spacing | gap: 8 |
empty (v1.2.0+)
|
A card to show when there are no copies. Used exactly as written: its placeholders are not filled | empty: {type: markdown, content: All quiet} |
lazy (v2.0.0+)
|
Builds copies only as they come near the screen, after the first few. Off in the editor's preview and while debugging | lazy: true |
lazy_eager (v2.0.0+)
|
How many copies lazy builds straight away. Defaults to 6 |
lazy_eager: 9 |
template_by_domain (v2.0.0+)
|
Lets each copy pick its own template by its entity's domain. Each one has to build a card | template_by_domain: {light: light_tile, default: plain_tile} |
grid_options (v1.2.0+)
|
The size of the whole repeat in a sections view | grid_options: {columns: full} |
More than 50 copies on one card logs a warning suggesting lazy: true. See
Repeating a Template.
A view strategy repeats sections and badges; a dashboard strategy repeats views. Each entry
under sections:, badges: or views: either is written out as it should appear, or is a
repeat:
| Key | What it does | Example |
|---|---|---|
for_each / for_each_from
|
What to repeat over, exactly as on a card | for_each_from: {areas: true} |
section / badge / view
|
What each copy is. Its placeholders are filled from the copy, and every templated card inside it is handed the copy's values | section: {type: grid, cards: [...]} |
variables |
Values every copy of this entry gets | variables: {colour: teal} |
empty |
What to show when nothing matches. Used as written | empty: {type: grid, cards: []} |
An entry with a repeat but no section:, badge: or view: produces nothing. A views:
source inside a dashboard strategy produces nothing either, since there are no views yet.
Generated view paths are made safe for a URL (Living Room becomes living-room), and a
path someone wrote by hand keeps it.
More: The view strategy, The dashboard strategy, Repeating Sections and Badges.
(v2.3.0+)
repeat: puts a copy of an entry into a card's own list once per item, rather than
repeating the whole card:
entities:
- '[[row|repeat:lights]]' # one row per light, spliced into the list
- type: dividerrepeat: reads a list variable, or a variable holding any for_each_from mapping. Each
copy gets the item's keys (a plain value is item, and entity too when it looks like an
entity id) plus index, index0, count, first and last. Copies that come out empty
are dropped (v2.3.2+). A template: source gives no copies here.
More: List Entries, with: and repeat:.
Work down this list.
| Check | Why |
|---|---|
Does for_each_from name a source or a filter? |
sort, limit, group_by, include_hidden, entity_category and the like alone are not a repeat: the card builds once, as if there were no repeat |
| Is the filter one this source reads? | Which filters each source reads: a filter it does not read is ignored, which shows more, not less |
| Are the entities hidden, or diagnostic or config ones? | A sweep leaves those out (v2.0.0+). Add include_hidden: true or entity_category: all (inside with: for area and other sources) |
| Is the pattern matching the whole id? |
kitchen is not kitchen_island. Use *
|
Is group_by one of domain, area, floor, label? |
Anything else gives no copies |
Does require name a value the copies carry? |
A name nobody carries drops every copy |
Does the template declare a variable required: true? |
Copies with nothing for it are dropped |
Is it filtering by category or label names? |
Those registries are fetched after the page loads; give it a moment |
Is it a template: source? |
It must render a list; the browser console says what it got instead |
Is it a views: source in a dashboard strategy? |
There are no views to list yet |
The card editor's match preview shows what a for_each_from matches right now, and
debug: console shows every
copy's values.
- Repeating a Template: the how-to, with examples for each source.
- Configuration Reference: every other key.
- Placeholder Reference: every placeholder step.
Getting started
Core concepts
Content types
Features
- Repeating a Template
- Repeating Sections and Badges
- List Entries
- Sharing Between Dashboards
- Sharing a Template
- Visibility
- Styling
- Visual Editors
- Translations
Reference