Your card already knows.
Let it show.

A static module shows one icon, one colour, one number. Turn on Template Mode and a short Jinja2 template decides those every time your entities change, so one module reports level, status and urgency at once. Everything on this page is live: the previews are the real Ultra Card modules, evaluating the real templates against a simulated home you can drive yourself.

14Places to use them
11Context variables
43Return properties
34Worked examples
Why bother?

The same module, twice.

On the left, a normal module. On the right, the identical module with one template added. Drag the temperature and watch which one reacts. That difference is the whole feature.

This drives the demo entity, exactly like a real sensor reporting a new value.

Playground

Build one. Watch it run.

Pick where the template lives, build it with the form or write it by hand, and see the real module render it. Nothing here is saved or sent anywhere. When it looks right, copy it into your card.

Set these properties
Live module
What the template returned
Waiting for the first render…
Simulate your home
Every place it works

Fourteen switches, one language.

Template Mode is the same Jinja everywhere: only the properties you return change. Here is what each one controls and why you'd reach for it.

Reference

What goes in, what comes out.

Variables are handed to your template; properties are what you hand back. Both lists are read straight from the card, and the variable column below is resolving live right now.

Context variables

Available when the module is bound to an entity. Text, Markdown and QR templates have no entity of their own, so name one with states('sensor.x') instead.

Return properties

Return a JSON object with any of these. Return a plain string instead and each module interprets it sensibly: an icon name for Icon, body text for Text, an entity id for Camera.

Field notes

The things that trip people up.

Six habits that turn "why is it blank?" into a template that just works.

Keep Jinja inside the quotes

The template renders first, then the result is parsed as JSON. So the Jinja has to sit inside the string it produces, not around the key.

✗ "icon": {% if hot %}"mdi:fire"{% endif %}
✓ "icon": "{% if hot %}mdi:fire{% else %}mdi:snowflake{% endif %}"

Numbers and booleans go outside

Values that aren't strings (value, pie_fill, card_border_radius, fill_area) are emitted bare. Jinja prints True, which looks wrong but is fine: Home Assistant evaluates the result as a Python literal before the card sees it.

✓ "value": {{ state | float(0) }},
  "fill_area": {{ is_state('input_boolean.fill','on') }}

state is an input, state_text is an output

{{ state }} is the entity's value coming in. The property that sets the text a module displays is state_text. Returning state also works (it's accepted as an alias because everyone tries it), but the others have no such alias, so a typo just does nothing. Unknown keys are flagged under the editor.

Hiding things is a different switch

A module template controls how a module looks, never whether it appears. To show and hide, use Display Conditions on the module, or Template Mode on the row or column and return visible.

Name entities with states()

Home Assistant watches the entities your template mentions and re-renders only when they change. Reading states('sensor.x') lets it track that for you. The snapshot variables (state, attributes) are handed in per render instead, so Ultra Card has to resubscribe when they move. Both are correct, but states() is the lighter path for wall tablets.

Reuse values with $variables

Define a variable once in the Hub and drop $living_room_temp into any template; Ultra Card substitutes it before Home Assistant renders. Need a literal dollar sign? Write $$.

Templates are free. All of them.

Template Mode ships with Ultra Card: no subscription, no account. Install from HACS and the same cheatsheet you just used is a click away inside every module editor.

Secret Link