Skip to content

Placeholder Reference

tempus2016 edited this page Oct 31, 2026 · 5 revisions

Placeholder Reference

Everything that can go inside [[ ]], one row each, with what it gives back. This page is for looking something up: what a step is called, what it does with an empty value, whether it gives a number or text. For why you would use one, and longer examples, follow the link in each section to Variables.

Every example on this page has been run through the card. Where a result is quoted, as in "5", it is text; unquoted numbers, true and false are real values.

Not sure what something does? Try a placeholder shows what each step of a chain gives out, in your browser, without touching a dashboard.

On this page: How a placeholder is written · Text · Text with an argument · Lists · Sums · When there is no value · Yes or no · Asking Home Assistant · List entries · What comes out: text or a real value · Which value wins · Limits


How a placeholder is written

name: '[[room|trim|title|default:Somewhere]]'
#       └─┬┘ └──────────┬─────────────────┘
#     variable   steps, run left to right
Form What it does Example Result
[[name]] The variable's value entity: '[[light]]' with light: light.hall light.hall
[[name|step]] (v1.1.0+) The value, passed through one or more steps, left to right '[[room|slug|upper]]' with room: Back Garden BACK_GARDEN
[[name?]] (v1.1.0+) Optional: with no value, the key it sits on is removed (see below) name: '[[label?]]' with nothing set the name key is gone
[[!name]] (v1.1.0+) Escaped: written out as the text [[name]], never substituted content: 'Type [[!entity]]' Type [[entity]]
[[a.b]] (v1.2.0+) A key inside a variable that holds a mapping, up to three keys down '[[room.light]]' with room: {light: light.hall} light.hall
[[a.chosen]] (v2.6.0+) What a choose selector picked: the value under the key its active_choice names. A real chosen key wins '[[dims.chosen]]' with dims: {active_choice: Ratio, Ratio: '16:9'} 16:9
[[a.[[b]]]] (v1.15.1+) A key picked by another variable: the inner placeholder is filled first [[colours.[[level]]|default:grey]]' with colours: {error: red}, level: error red

Rules that apply to every placeholder:

  • Steps run left to right, each one working on what the last one gave. A step that asks Home Assistant reads its value as an entity id, so it goes before anything that reshapes it: [[entity|friendly_name|upper]], not [[entity|upper|friendly_name]].
  • The ? goes last, after every step: [[room|slug?]].
  • No spaces round the bar. [[room | slug]] is not a placeholder, and neither is one with a misspelt or upper-case step: the card leaves it exactly as written, so you can see it.
  • An argument runs from the colon to the next | or ]]. It can hold spaces and colons (default:mdi:home is fine), but never |, [ or ] written as text. There is no escape character. A whole placeholder can stand in as the argument (default:[[room]], add:[[offset]]), because it is filled in first.
  • A ? written against the closing brackets is always the marker, never part of an argument: [[who|prefix:Mr ?]] is an optional who with Mr in front.
  • Placeholders work in keys too, not only values: '[[key]]': on.
  • Name a variable anything except with [, ] or | in it, starting with ! or ending with ?. Spaces and dots are allowed, though a dot reads as a lookup into a mapping first.
  • A placeholder nothing fills is left as written, and the browser console says which. That is on purpose: [[room]] showing on a card is far easier to spot than a blank. See Unresolved placeholders.

More: Writing placeholders, Value types.


Text

Each of these does one fixed thing to text. A number or true/false is shaped as its text, a null as the word null, and an empty value stays empty. A mapping or a list is refused: the placeholder is left as written, because uppercasing JSON would only garble it. The result is always text.

Step What it does Example Result
slug Lower case; every run of anything but a letter or digit becomes one _, trimmed from the ends 'light.[[room|slug]]' with room: John's Back Garden light.john_s_back_garden
kebab (v1.1.0+) As slug, with - '[[room|kebab]]' with room: Back Garden back-garden
upper Upper case '[[room|upper]]' with room: Hall HALL
lower Lower case '[[room|lower]]' with room: Hall hall
title First letter of every word upper case, the rest lower case '[[room|title]]' with room: back GARDEN Back Garden
capitalize (v1.3.0+) First character upper case, everything else left alone '[[room|trim|capitalize]]' with room: ' living room' Living room
trim (v1.3.0+) Whitespace removed from both ends '[[room|trim]]' with room: ' Hall ' Hall

slug only keeps the letters a to z, so accented letters go: Café becomes caf. Order matters in a chain: [[room|slug|upper]] gives JOHN_S_BACK_GARDEN, while [[room|upper|slug]] gives john_s_back_garden, because slug lower-cases.

More: Asking for a variable in a different shape.


Text with an argument

(v1.4.0+, except find:)

Step What it does Example Result
replace:from:to Every from becomes to. Leave :to off to delete. from is everything up to the first colon, so it cannot be a colon itself '[[room|replace:_: ]]' with room: living_room_lamp living room lamp
prefix:text text in front. An empty value stays empty, so ? and default: still see a gap '[[room|prefix:light.]]' with room: hall light.hall
suffix:text text after; an empty value stays empty '[[n|suffix: sensors]]' with n: 3 3 sensors
max:n At most n characters, the last of them replaced by …. Anything that is not a positive number leaves the value alone '[[name|max:10]]' with name: Kitchen temperature Kitchen t…
map:a=x,b=y Looks the value up in the pairs. *=z catches anything not named, wherever it is written. Matching is exact and case-sensitive. No match and no *: the placeholder is left '[[level|map:low=green,high=red,*=grey]]' with level: high red
find:text (v2.0.0+) Where text first appears, counting from 0, or -1. A real number '[[id|find:car]]' with id: camera_1_car 9

In map:, each pair splits at its first =, so a result may contain = but a value to match may not, and neither may contain a comma. =none matches an empty value: map:=none,*=some.

An argument can hold a placeholder, which is filled in first (v2.5.0+): [[room|lower|suffix:_[[kind]]]] with room: Hallway, kind: motion gives hallway_motion. Before v2.5.0 the argument stopped at the inner ].

More: Transforms that take an argument, find:.


Lists

(v2.0.0+)

Text is read as a list by splitting it at commas, trimming each item and dropping empty ones. A variable that already holds a list is used as it is. These steps go first in a chain, or straight after split.

Step What it does Example Result
join / join:sep The items as one line of text, , between them, or sep. join: puts nothing between '[[rooms|join: / ]]' with rooms: [Kitchen, Hall] Kitchen / Hall
split / split:sep Text made into a real list, at commas or at sep. Text steps after it shape each item '[[ids|split]]' with ids: 'light.a, light.b' [light.a, light.b]
first The first item, as text '[[rooms|first]]' with rooms: [Kitchen, Hall] Kitchen
last The last item, as text '[[rooms|last]]' with rooms: [Kitchen, Hall] Hall
count How many items, or how many keys in a mapping. Unset, null or empty counts as 0. A real number '[[rooms|count]]' with rooms: [Kitchen, Hall] 2

After split, steps run on every item: [[rooms|split|slug|join:,]] with rooms: 'Back Garden, Front Door' gives back_garden,front_door. first and last give text even for a list of numbers: [[l|first]] on [1, 2] is "1".

More: Lists.


Sums

(v2.0.0+)

The value has to be a number, or text that is one ('3' works). Anything unusable, and dividing by zero, leaves the value exactly as it was, with a warning in the console. Results are real numbers, except pad, which is always text.

Step What it does Example Result
add:n Adds n '[[index|add:1]]' with index: 3 4
sub:n Subtracts n '[[index|sub:1]]' with index: 3 2
mul:n Multiplies by n '[[t|mul:2]]' with t: 21.5 43
div:n Divides by n. div:0 leaves the value alone '[[w|div:1000]]' with w: 2500 2.5
mod:n The remainder after dividing by n, with the sign of the value '[[index|mod:2]]' with index: 5 1
round / round:n To a whole number, or to n places (0 to 15) '[[t|round:1]]' with t: 21.456 21.5
pad:n A whole number written with leading zeros to n characters (1 to 64), sign included. Always text '[[h|pad:2]]' with h: 7 "07"

The number after the colon can itself be a placeholder: [[index|add:[[offset]]]]. Sums chain: [[index|sub:1|mul:12|add:4]] with index: 3 is 28, and [[t|mul:9|div:5|add:32|round:1]] turns 21 into 69.8.

round:2 gives 2.50 inside text ([[t|round:2]] kWh' is 2.50 kWh) but 2.5 as a whole value, because a real number has no trailing zeros. Add text round it, or pad, when the zeros matter.

More: Sums.


When there is no value

A value counts as missing when it is not set, is null, or is empty text. 0 and false are values. With ?, an empty mapping {} is missing too (v2.6.0+), so [[size?]] with size: {} drops the key; without ? it is still a value.

Step What it does Example Result
default:text (v1.2.0+) text when the value is missing, or when a step before it found nothing. May hold spaces and colons. Empty (default:) gives empty text '[[name|default:Unnamed]]' with nothing set Unnamed
or:other (v1.2.0+) Another variable's value when this one is missing. Chain several '[[name|or:label|default:Unnamed]]' with label: Hall Hall
[[name?]] (v1.1.0+) The key is removed when the value is missing (see the list below) icon: '[[icon?]]' with nothing set no icon key
json (v1.2.0+) The value written as JSON text: a mapping or list kept whole, a string quoted. Only as the first step '[[tap|json]]' with tap: {action: toggle} {"action":"toggle"}

What ? removes (v1.1.0+; emptied blocks v1.12.0+):

  • a key whose whole value is the placeholder;
  • a list item that is only the placeholder;
  • any mapping or list left empty by those removals, all the way up; a block you wrote empty yourself ([], {}) is kept;
  • inside longer text, just the placeholder: 'x/[[n?]]' becomes x/.

Things worth knowing:

  • Steps after default: shape the stand-in as well: [[name|default:back garden|title]] gives Back Garden. Steps before it only shape a real value.
  • default: can hold a placeholder: [[name|default:[[room]]]].
  • default: and or: make the result text. [[n|default:0]] with n: 5 gives "5", not 5. Leave them off a value that must stay a number or a boolean, and give the default in the template's default: list instead.
  • [[name|default:?]] drops the key when nothing is set (v1.13.0+).
  • or: can borrow a mapping or a list (v2.6.0+) when the placeholder is the whole value: block: '[[size|or:default_size]]' puts the mapping in whole. Inside longer text it still cannot, and the gap stays. Before v2.6.0 it never could.
  • A mapping or list that is set passes through default: and or: untouched (v2.4.0+), the same as [[name]] on its own.

More: Standing in for what nothing set, A variable the template can do without, Putting a mapping in on purpose.


Yes or no

Step What it does Example Result
bool (v1.12.0+) A real true or false. No: not set, null, false, 0, an empty list or mapping, and the words no, off, false, 0 or empty text, in any case. Yes: anything else hide_state: '[[compact|bool]]' with compact: 'yes' true
if:other (v1.12.0+) Keeps the value only while other is a yes (read as bool reads it); otherwise it counts as missing '[[colour|if:alarm]]' with colour: red, alarm: false missing, so left as written
if:other=text (v1.12.0+) Keeps the value only while other is exactly text '[[colour|if:mode=night|default:amber]]' with mode: day amber
if:!other (v2.0.0+) Keeps the value only while other is a no, or not set '[[note|if:!compact?]]' with compact: true the key is gone
if:other!=text (v2.0.0+) Keeps the value only while other is anything but text, not set included '[[colour|if:mode!=off]]' with colour: teal, mode: auto teal
exists (v2.0.0+) true when Home Assistant knows this entity id, as a state or in the entity registry. Not set or empty is false '[[sensor|exists]]' with sensor: binary_sensor.hall_motion true
if_exists (v2.5.0+) Keeps the entity id only while Home Assistant knows it, as exists reads it; otherwise it counts as missing - '[[sensor|if_exists?]]' with sensor: binary_sensor.attic_motion, which does not exist the list item is gone
contains:text (v2.0.0+) On text, true when text is in it. On a list, true when an item is exactly text. On a mapping, true when it has that key (v2.4.0+). Not set is false '[[name|contains:door]]' with name: Outdoor Lights true

An if: that does not hold, or an if_exists that finds nothing, makes the value missing, so pair it with ? to drop the key, or default: to use something else. Every if: in a chain has to hold, wherever it is written. The variable if: reads may be dotted (if:room.on); the text after = is compared as text, so if:count=3 matches the number 3.

bool, exists and contains: put in a real true or false when they are the whole value, and the word true or false inside longer text. Further steps can turn the answer into anything: [[compact|bool|map:true=Compact,false=Full]].

More: Switching an option on and off, Keeping a value only while another variable says so, exists, contains: and find:.


Asking Home Assistant

These read the value as an entity id and answer from Home Assistant. When there is nothing to give (no such entity, no area, no device) the placeholder is left as written, and a default: or or: after it stands in. The answer is always text, and Home Assistant's words are never read as placeholders or as another card's code.

An entity's area is its own, or its device's when it has none.

Step What it gives Example, for light.kitchen_ceiling Result
friendly_name (v1.1.0+) The entity's name '[[entity|friendly_name]]' Kitchen Ceiling
area (v1.1.0+) The name of its area '[[entity|area]]' Kitchen
device (v1.1.0+) The name of its device '[[entity|device]]' Ceiling Light
attr:name (v1.1.0+) One of its attributes. A list attribute comes out as a, b, a mapping as its JSON (v2.4.0+). access_token and entity_picture are never given out, nor anything carrying a token= '[[entity|attr:brightness]]' "200"
floor (v1.2.0+) The name of its area's floor '[[entity|floor]]' Ground Floor
area_id (v1.2.0+) Its area's id '[[entity|area_id]]' kitchen
device_id (v1.2.0+) Its device's id '[[entity|device_id]]' 3f9c…
domain (v1.7.0+) The part before the dot. Needs no Home Assistant, only something shaped like an entity id '[[entity|domain]]' light
object_id (v1.7.0+) The part after the dot, likewise '[[entity|object_id]]' kitchen_ceiling
labels (v1.7.0+) The names of the entity's own labels, , between them. A device's labels are not included '[[entity|labels]]' Lights, Downstairs
icon (v2.0.0+) Its icon, set in the registry or by the integration; empty text when it has none '[[entity|icon]]' mdi:ceiling-light
device_class (v2.0.0+) Its device class '[[sensor|device_class]]' on sensor.kitchen_temperature temperature
manufacturer (v2.0.0+) Its device's manufacturer '[[entity|manufacturer]]' IKEA
model (v2.0.0+) Its device's model '[[entity|model]]' TRADFRI bulb
area_icon (v2.0.0+) Its area's icon; empty text when the area has none '[[entity|area_icon]]' mdi:stove
floor_icon (v2.0.0+) Its floor's icon; empty text when the floor has none '[[entity|floor_icon]]' mdi:home-floor-0
translate (v2.0.0+) Home Assistant's own word in the dashboard's language: an integration's name for a word without a dot, a translation key for one with. Never left: anything untranslated comes back as written '[[entity|domain|translate]]' Light
state (v2.0.0+) Its state, only for an entity listed in the card's rebuild_on; anything else is left, and default: does not cover that '[[mode|state]]' with rebuild_on: input_select.mode Away

domain, object_id and the steps after them chain like any others: [[entity|object_id|replace:_: |title]] gives Kitchen Ceiling without asking Home Assistant for a name. An entity listed in rebuild_on can be named directly: [[input_select.mode|state]].

translate on a whole entity id treats it as a translation key and gives it back unchanged, so it goes after domain: [[entity|domain|translate]].

More: Asking Home Assistant for a value, Following an entity's state.


List entries

(v2.3.0+)

These two build whole blocks rather than text, and each has to be the only step in its placeholder, apart from |flat after a repeat: (v2.4.0+). The block is an item template's item:, or a variable that holds a mapping.

Step What it does Example Result
with:k=v,k2=v2 The block once, filled in with those values. Values are always text - '[[row|with:entity=sun.sun,name=Sun]]' with row: {entity: '[[entity]]', name: '[[name]]'} - {entity: sun.sun, name: Sun}
with:var The same, with the values from a variable holding a mapping - '[[camera_entry|with:front]]' with front: {camera_entity: camera.front} - {camera_entity: camera.front, live_provider: go2rtc}, the rest from camera_entry's defaults
repeat:var The block once per item of a list, or once per thing a registry source finds, spliced into the list it sits in - '[[row|repeat:lights]]' with lights: [{entity: light.a}, {entity: light.b}] - {entity: light.a, …} and - {entity: light.b, …}
with (v2.5.0+) The same as with: with nothing after the colon: the block filled in from the values the card already has, item template defaults included - '[[row|with]]' with entity: light.kitchen on the card - {entity: light.kitchen, …}
repeat (v2.5.0+) An item template repeated over its own for_each list or for_each_from source - '[[every_light|repeat]]' with every_light: {for_each_from: {domain: light}, item: …} one entry per light
repeat:var|flat (v2.4.0+) The same, with each copy that is itself a list laid out in the outer list, so a repeat inside a repeat gives one flat list - '[[per_type|repeat:detect_list|flat]]' one entry per row of every copy

A variable holding a fill, p: '[[probe|with:n=front_door]]', also offers the item template's own values by dotted name (v2.4.0+): [[p.found]], if:p.found. See Reading what a fill worked out.

Each repeat: copy gets the item's keys (or item for a plain value, and entity as well when that value is an entity id), plus index, index0, count, first and last. Copies that come out empty are dropped (v2.3.2+).

Inside the fill, an item template's own let: wins, then the with: values, then everything the card already had, then the item template's default:.

More: List Entries.


What comes out: text or a real value

A placeholder that is the whole value keeps its type; one inside longer text is always text.

The value is As the whole value Inside text
text text, even when it looks like a number ('12' stays "12") as written
a number a number its digits
true / false a boolean the word
a mapping or a list the structure itself its JSON
null null the word null
empty text empty text nothing

Once there are steps, the result is text, except when the last step that does something is one of these:

Ends in Gives
bool, exists, contains: a real true or false
add sub mul div mod round count find: a real number
split, and text steps after it a real list
with:, repeat: the filled block
only if: steps the value untouched, mapping or list included

default:, or: and if: are not counted as "the last step" after a sum, count, find: or split: [[t|round|default:0]] is still a number when t is set. After bool, exists or contains:, though, a default: or or: turns the answer into the text "true" or "false". Leave them off when an option needs a real boolean; bool already answers for an unset value. pad, first, last, json and everything that asks Home Assistant give text. So does a value passed through default: or or: alone.

More: Value types.


Which value wins

When more than one place gives the same name a value, the first in this list wins.

Where Set by Page
1 The template's let: (v1.7.0+) the template Variables
2 The section's decluttering_let (v2.0.0+) the dashboard Variables
3 The view's decluttering_let (v2.0.0+) the dashboard as above
4 The dashboard's decluttering_let (v2.0.0+) the dashboard as above
5 variables: on the card (for a repeated card: the item's values, then the card's variables:, then index and friends) the card Using Templates
6 The section's decluttering_defaults (v1.10.0+) the dashboard Sharing Between Dashboards
7 The view's decluttering_defaults (v1.9.0+) the dashboard as above
8 default inside a declaration in the template's variables:, or in a shared decluttering_variables declaration of the same name (v1.13.0+) the template Describing Variables
9 The template's default: list the template Variables
10 The template's defaults: list (v2.0.0+) the template as above
11 The dashboard's decluttering_defaults (v1.1.0+); for a borrowed template, this dashboard's, then the lender's the dashboard Sharing Between Dashboards
12 An entity listed in the card's rebuild_on, standing for itself (v2.0.0+) the card Variables
13 An item template, standing for its block (v2.3.0+) the template List Entries

Within one list, the first entry for a name wins. A shared decluttering_variables declaration only applies to a name the template declares itself.

In short: let is worked out and cannot be overridden; variables: on the card beats every default; and the nearer a default is to the card (section, then view, then template, then dashboard), the more it counts.


Limits

Limit What happens
10 passes Substitution repeats until nothing changes, at most 10 times. A variable that refers to itself stops there, with a console warning. A chain of variables that refer to each other settles in one pass when they are listed in the order they are used, one link per pass when listed backwards
A template that uses itself Refused outright (v1.2.0+). See Troubleshooting
3 keys down [[a.b.c.d]] is as deep as a dotted name reaches. List items cannot be picked by number
6 deep with: and repeat: blocks inside each other
2000 fills with: and repeat: copies in one card

Next

Clone this wiki locally