Template Select Entities

Template Selects create an entity that acts like an Input Select Helper in the front end, but more like an automation behind the scenes. Their options list can be either static or dynamically generated by a template. Often, a helper entity will be required to store the state value for the Template Select. Either Input Text or Trigger-based Template Sensors can be used for this purpose.

Template Selects in place of an automation

This is the most general use type for a Template Select.

Example: Source Selector for Legacy equipment

In the following example, a Select is used to switch sources on an old stereo receiver. The select_option sequence shown below saves the selected value to an Input Text helper and passes it along to a script that handles sending IR commands to the stereo receiver.

template:
  - select:
      - name: "RCA Stereo Source"
        unique_id: rca_stereo_source_select
        state: "{{ states('input_text.rca_receiver_output') }}"
        options: "{{ ['Cable', 'CD','AUX', 'AM/FM', 'DVD'] }}"
        select_option:
          - service: input_text.set_value
            target:
              entity_id: input_text.rca_receiver_output
            data:
              value: "{{ option }}"
          - service: script.rca_receiver_send_command
            data:
              command: "{{ option }}"
              repeats: 2
        availability: "{{ states('input_text.rca_receiver_output') is defined }}"
Example: Entraining Booleans / Only one "on" at a time

In this example the options are automatically populated with the entity IDs of all input_boolean entities that match a specific naming scheme. The state and options are presented in the form of entity IDs. The select_option sequence turns the selected entity ‘on’. Then, all the non-selected booleans are turned ‘off’.

template:
  - select:
      - name: "Partially Entrained Booleans"
        state: >-
          {{ (expand(this.attributes.options
          | select('is_state', 'on')
          | list) | sort(attribute='last_changed', reverse=1)
          | map(attribute='entity_id')|list)[0] or
          (expand(this.attributes.options) | sort(attribute='last_changed', reverse=1)
          | map(attribute='entity_id')|list)[0]}}
        select_option:
          - service: input_boolean.turn_on
            target:
              entity_id: "{{ option }}"
          - variables:
              boolean: |
                {{ this.attributes.options |reject('eq', option)|list}}
          - service: input_boolean.turn_off
            target:
              entity_id: '{{ boolean }}'
        options: >
          {{ states.input_boolean
          | selectattr('object_id', 'match', 'test_bool_')
          | map(attribute='entity_id')
          | list }}

Proxy/Translate an Existing Select or Input Select entity

Sometimes you need to “edit” the option list of a Select entity that was created by another integration.

  • If the options are not labelled in a way that you like.
  • If the option names are not easily understood by people in your household. For example, some HVAC integrations will have numeric options. It’s much easier to work with normal mode names rather than trying to remember that 101 is “off”, 102 is “heat”, and 121 is “cool”…
  • If the list includes options that you want to exclude.

Or, you may live in a bilingual household, and want to have a version in each language, but keep their states entrained.

Example: Translating Options
template:
  - select:
      - name: "Color Picker"
        unique_id: seleccionador_de_colores_translated_to_english
        state: >
          {% set opt = states('select.seleccionador_de_colores') %}
          {% set mapper = {
            'Rojo': 'Red',
            'Azul': 'Blue',
            'Verde': 'Green',
            'Amarillo': 'Yellow',
            'Blanco': 'White'
          }%}
          {{ mapper.get(opt) }}
        options: "{{['Red','Blue','Green','Yellow','White']}}"
        select_option:
          - service: select.select_option
            data:
              option: >
                {% set mapper = {
                  'Red': 'Rojo',
                  'Blue': 'Azul',
                  'Green': 'Verde',
                  'Yellow': 'Amarillo',
                  'White': 'Blanco'
                }%}
                {{ mapper.get(option) }}
            target:
              entity_id: select.seleccionador_de_colores
        availability: "{{ state_attr('select.seleccionador_de_colores', 'options') is defined }}"

Area-based Scene Selector

The following examples show two ways to create a selector for all the scenes assigned to a given Area. The state and options are presented in the form of friendly names for UI usability. In both of the following examples, selecting a scene activates that scene.

Helper-free Version
template:
  - select:
      - name: "Basement Scenes"
        state: >
          {% set area = "Basement" %}
          {{ 
            expand(area_entities(area))
              | selectattr('domain', 'eq', 'scene')
              | sort(attribute='state', reverse=true)
              | map(attribute='name')
              | list
              | first
          }}
        options: >
          {% set area = "Basement" %}
          {{
            expand(area_entities(area))
              | selectattr('domain', 'eq', 'scene')
              | map(attribute='name')
              | list
              | sort
          }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{
                  states.scene
                    | selectattr('name', 'eq', option)
                    | map(attribute='entity_id')
                    | first
                }}

This method was originally posted by @TheFes in another thread

Helper entity Version

This example uses a trigger-based Template sensor as the helper entity, this makes for a tidy package when using YAML configuration, but similar end results could be achieved using an Input Text Helper as shown in previous examples. Also included is “reset” option. This is optional, but can be helpful if the entities controlled by your scene have been changed and you want to reinstate the scene without making everything transition through another scene.

template:
  - select:
      - name: "Basement Scenes"
        state: "{{ states('sensor. basement_scenes_helper') }}"
        options: >
          {{ expand(area_entities(area)) | selectattr('domain', 'eq', 'scene')
          | map(attribute='name') | list + ['Reset'] }}
        select_option:
          - event: custom_template_select
            event_data:
              target: basement_scenes
              value: "{{ option }}"
          - if:
              - condition: template
                value_template: "{{ option != 'Reset'}}"
            then:
              - variables:
                  entity: >
                    {{ states.scene | selectattr('name', 'eq', option) | map(attribute='entity_id') | join }}
              - service: scene.turn_on
                target:
                  entity_id: "{{ entity }}"
  - trigger:
      - platform: event
        event_type: custom_template_select
        event_data:
          target: basement_scenes
    sensor:
      - name: Basement Scenes Helper
        unique_id: basement_scenes_helper_0001
        state: "{{ trigger.event.data.value }}"

Merged Options

This example shows how to effectively combine two Select or Input select helpers so you can have a single selector on your dashboard:

Merging Audio Source Selectors
template:
  - select:
      - name: "Merged Audio Selects"
        state: >
          {{expand('input_select.radio_stations','input_select.music_genres')
          | sort(attribute='last_changed', reverse=true)
          | map(attribute='state')
          | list | first}}
        options: >
          {{ state_attr('input_select.music_genres', 'options')
          + state_attr('input_select.radio_stations', 'options') }}
        select_option:
          - service: input_select.select_option
            target:
              entity_id:
                - input_select.music_genres
                - input_select.radio_stations
            data:
              option: "{{ option }}"

Trigger-Based Template Selects

The ability to use triggers, variables, actions, and conditions with a template select has now been added. Currently (2025.6), with this new variety the state and options are only updated following a trigger. As such, the entity will be unusable until it is triggered at least once, since there will be no options to choose from; also in order for the select_option action to have an effect on the state you will need to include an action that will fire a trigger.

Trigger-based Self-Resetting

This example demonstrates triggering on the select’s own state to set it back to a default state after a desired duration.

Self-Resetting Select
template:
  - trigger:
      - trigger: state
        entity_id: select.self_resetting_select
        not_to: 'Default'
        for: '00:01:00'
        id: default
      - trigger: homeassistant
        event: start
        id: default
      - trigger: event
        event_type: custom_select_event
        event_data:
          entity_id: select.self_resetting_select
        id: selection
    select:
      - name: Self-Resetting Select
        optimistic: true
        state: "{{ 'Default' if trigger.id == 'default' else trigger.event.data.option|default('Default',1) }}"
        options: "{{ ['Default','Option_1','Option_2','Option_3']  }}"
        select_option:
          - event: custom_select_event
            event_data:
              entity_id: "{{this.entity_id}}"
              option: "{{option}}"

Call for Assistance/Submissions:

If you run across a use case or example that you feel is especially helpful or doesn’t fit any of the sections above, please add it to this post along with a brief explanation of what you use it for.


Home Assistant Docs - Template Integration - State-based - Select

The Home Assistant Cookbook - Index

17 Likes

Is there a way to have a self contained template select?

Say I have ['opt1', 'opt2', 'opt3']

I select opt3

So the state would be opt3 and the options would be ['opt3', 'opt1','opt2']

Or even keep the options list static?? Not sure.

Something like…

template:
  - select:
      - name: "my_template_select"
        state: >-
          {{ this.attributes.options | list | first }}
        select_option: >
          {{ move the selected option to the first index here }}
        options: >
          {{ this.attributes.options }}

Your question is a bit confusing… one of the major points that Template selects are meant to address is when you can’t say what options you have. The example configuration you have provided, with static options, is just an over-complicated Input Select.

If you look in the Area-based Scene Selector section above, you can see an example of the closest thing to a self-contained option that I know of… though it is not exactly self-contained. There are a couple issues with creating something like what you have described.

Issue #1: Unlike input_select, the select domain doesn’t currently have a set_options action, so there’s no current way to “move the selected option to the first index”. Such an action could have serious negative impacts if used on select entities from integrations other than Template, so I doubt we will ever see it in core. This might be something that Frenck would consider adding to Spook… but AFAIK it doesn’t exist currently.

Issue #2: You would have to at least start with a static list to define options. In the YAML only days that would mean that the value of options would set back to the original values after restart… I’m not familiar enough with how the UI config works under the hood to say how it would work for a select configured through the Template Helper UI.

I have bellow template select

- select:
    - name: "Doc Tin VTV24 Da Chon Ra Loa"
      unique_id: select_doc_tin_vtv24_da_chon_ra_loa
      state: |
        {{states('input_text.doc_tin_vtv24_da_chon_ra_loa')}}
      options: |
        {% set video_entries = state_attr('sensor.vtv24_youtube_channel','entries') |sort(attribute='published', reverse=true)%}{% set video_titles = video_entries |map(attribute='title') |list %}{{video_titles}}
      select_option:
        - service: input_text.set_value
          target:
            entity_id: input_text.doc_tin_vtv24_da_chon_ra_loa
          data:
            value: |
              {% set selected_title = option %}
              {% set video_entries = state_attr('sensor.vtv24_youtube_channel','entries') |sort(attribute='published', reverse=true)%}
              {% set video_titles = video_entries |map(attribute='title') |list %}
              {% set video_urls = video_entries |map(attribute='link') |list %}
              {# Chọn tiêu đề cần tìm URL #}
              {% set index = video_titles.index(selected_title) if selected_title in video_titles else -1 %}
              {% if index != -1 %}
                {{ video_urls[index] }}
              {% else %}
                Không tìm thấy tiêu đề trong danh sách!
              {% endif %}
      availability: "{{ states('input_text.doc_tin_vtv24_da_chon_ra_loa') is defined }}"
      optimistic: true

Why states of select alway unknown when i changed option


State of input_text has changed.

FYI template selects do not behave as they should IMO. Will be updating that in a future PR.

TLDR: Assumed/optimistic state does not work as it should.

1 Like

I switched from using input_selects to templates, partly because of this thread, but also because I’m having a UI issue I was hoping using template selects might address.

After restarting home assistant sometimes (not always) the UI isn’t refreshed and that leaves the selects (as well as input_selects) in the UI blank – event though the states are updated in dev console and refrshing the browser shows the correct states.

I do trigger on HA restart to refresh the select. I use a separate input_text to store the state of the select.

I’m curious if anyone else is seeing this. Not a huge deal as can simply refresh the screen.

  - triggers:

      # Trigger on restart to restore state
      - trigger: homeassistant
        event: start

      # Allow something external to update the select
      - trigger: state
        entity_id: input_text.select_primary

    select:
      - name: Primary
        unique_id: select_primary_id
        optimistic: true
        state: "{{ states('input_text.select_primary') }}"
        options: "{{ state_attr('sensor.select_config','primary') }}"
        select_option:
          - action: input_text.set_value
            target:
              entity_id: input_text.select_primary
            data:
              value: "{{ option }}"

I just now restarted and notice how the “Cascade Selects” are blank? (dev->states show that they do have the expected states.)

I see in the docs template selects have an optimistic mode now. Does this also survive restarts?

1 Like

I have several input_booleans and would like to use the suggested option “Template Selects in place of an automation.”

I used the .yaml example provided and created a template sensor in the file editor. This provides a selection helper that does exactly what it’s supposed to do: switch the individual input_booleans on or off:

Now I would like to use the UI to create the very same helper (better maintenance):

But I can’t get it to work.
I would also like to be able to customize the names displayed in the selection (instead of input.boolean_wohnzimmer_beleuchtung_standard, I only want “Standard” to appear there).

Can you help me with this? I’m not very familiar with yaml. I only have a rough understanding of what’s happening.

Here is my code:

- select:
      - name: "Lichtszenen-Auswahl"
        state: >-
          {{ (expand(this.attributes.options
          | select('is_state', 'on')
          | list) | sort(attribute='last_changed', reverse=1)
          | map(attribute='entity_id')|list)[0] or
          (expand(this.attributes.options) | sort(attribute='last_changed', reverse=1)
          | map(attribute='entity_id')|list)[0]}}
        select_option:
          - service: input_boolean.turn_on
            target:
              entity_id: "{{ option }}"
          - variables:
              boolean: |
                {{ this.attributes.options |reject('eq', option)|list}}
          - service: input_boolean.turn_off
            target:
              entity_id: '{{ boolean }}'
        options: >
          {{ states.input_boolean
          | selectattr('object_id', 'match', 'wohnzimmer_beleuchtung')
          | map(attribute='entity_id')
          | list }}

You’ll need to share what you have tried… a screenshot of the config flow that doesn’t have any of the fields filled out isn’t really helpful.

If all of your input booleans follow the same naming pattern you can use the map filter to get the “friendlier” value for options, but then you will then need to add back the rest of the entity ID in a number of places:

  - select:
      - name: "Lichtszenen-Auswahl"
        state: >-
          {%- macro prepend(root,pre) %}{{- pre~root -}}{%- endmacro %}
          {%- set opt_ents =  this.attributes.options|map('lower')
          |map('apply',prepend,'input_boolean.wohnzimmer_beleuchtung_')|list %}
          {%- set sorted_obj = opt_ents|expand|sort(attribute='last_changed', reverse=1)|list %}
          {{- (sorted_obj|selectattr('state', 'eq', 'on')|map(attribute='entity_id')|list)[0] 
          or (sorted_obj|map(attribute='entity_id')|list)[0]}}
        select_option:
          - service: input_boolean.turn_on
            target:
              entity_id: "input_boolean.wohnzimmer_beleuchtung_{{ option|lower }}"
          - variables:
              booleans: |
                {%- macro prepend(root,pre) %}{{- pre~root -}}{%- endmacro %}
                {{- set opt_ents =  this.attributes.options|reject('eq', option)|map('lower')
                |map('apply',prepend,'input_boolean.wohnzimmer_beleuchtung_')|list }}
          - service: input_boolean.turn_off
            target:
              entity_id: '{{ booleans }}'
        options: >
          {{ states.input_boolean | selectattr('object_id', 'match', 'wohnzimmer_beleuchtung_')
          | map(attribute='object_id') | map('replace', 'wohnzimmer_beleuchtung_','')
          | map('capitalize') | list }}
1 Like

Trigger based template entities, other than sensors and binary sensors, do not restore their state when HA restarts or templates get reloaded. In the case of selects this leads to bad UX in the front end with a blank select dropdown and an actual state of unknown.

So I came up with this template to use as a base for creating template selects that restore their states when HA restarts or templates get reloaded (yes a base template of a templated trigger based template entity). This can also be used as a base for other trigger based template entities that do not restore their state.
I’m not sure I’ve ever writen something that sounds so redundant :roll_eyes:

I hope someone else finds it useful.

template:
  - trigger:
      - trigger: event
        event_type: custom_select_event
      - trigger: event
        event_type: event_template_reloaded
        id: reload
      - trigger: homeassistant
        event: start
        id: reload
    select:
      - name: Select Entity Name
        state: |
          {{ states('sensor.select_entity_reload_value') if trigger.id is eq 'reload' and has_value('sensor.select_entity_reload_value')
              else trigger.event.data.option|default('', true) }}
        optimistic: true
        options: "{{ ['Option_1', 'Option_2', 'Option_3'] }}"
        select_option:
          - event: custom_select_event
            event_data:
              option: "{{ option }}"
    sensor:
      - name: Select Entity Reload Value
        state: "{{ this.state if trigger.id is eq 'reload' else trigger.event.data.option|default('', true) }}"

Also I’m curious if anyone knows if there’s any value to using something like this for the state’s default, |default(this.attributes.options[0], true).

This post really caught my eye. I posted above about trouble restoring state.

The real question is why doesn’t HA just save the select’s state? Is it any different than a sensor? Is there a reason other than it just doesn’t?

I wasn’t aware you could have two sensors with a single trigger. After all, these are dictionary keys, so that means you could have two different sensor types but not two of the same type. Is there documentation on that?

Anyway, it seems like you have to jump through some extra hoops that way.

When I tried your code, on startup, I kept getting errors about data key not in trigger.event.

Here’s what I came up with. Seem a bit easer if there’s a separate input_text to save the state.

input_text:
  my_select_state_saver:
    name: Foo Source Text

template:

  - triggers:
      - trigger: homeassistant
        event: start
      - trigger: event
        event_type: event_template_reloaded
    select:
      - name: My Reloading Select
        default_entity_id: select.my_select
        options: "{{ ['One','Two','Three' ] }}"
        state: >
          {{
            states('input_text.my_select_state_saver') if has_value('input_text.my_select_state_saver')
            else 'One'
          }}
        optimistic: true
        select_option:
          - action: input_text.set_value
            target:
              entity_id: input_text.my_select_state_saver
            data:
              value: "{{ option }}"

Kind of. I just have a hard-coded else 'One' but could also look up the first option.

BTW, the foo|default('',true) seems a bit odd. Doesn’t that true say if foo is false (e.g. the empty string) use the default – so default('',true) is saying turn an empty string into an empty string, right?

Similarly. in my example, you can NOT do this:

state: "{{states('input_text.my_select_state_saver') | default('One') }}"

because the state is never undefined. An undefined (None) entity has the “unknown” state.

Both the integration key template and the different entity platforms under it, like binary_sensor, expect a list…

… so you can have multiple platforms as well as multiple entities of the same type sharing the same list of triggers as well as variables, conditions, and actions:

template:
  - triggers:
      - trigger: time
        at: 
          - "12:00:00"
          - "12:16:00"
          - "15:00:00"
          - "15:16:00"
    binary_sensor:
      - name: BS One
        state: "{{ now().hour == 12 }}"
      - name: BS Two
        state: "{{ 0 < now().minute <= 15 }}"
    sensor:
      - name: Twelve or Fifteen
        state: "{{ now().hour }}"
      - name: Zero or Sixteen
        state: "{{ now().minute }}"

Every platform needs code for restore to work and I haven’t added it to select yet.

1 Like

Ya that’s the has_value('sensor.select_entity_reload_value') test in the select. state, the backup sensor hasn’t been initiated yet on its first rendering so the test will fail.

The test is not strictly needed so it can be removed to avoid initial errors, then both states just resolve as unknown. You have to actually select an option at least once to make this work.

I don’t see much of a difference. You’re using a state trigger (technically still an event) and I’m using an event trigger, both still need to reference an entity with a stored value. I try not to use ‘input’ helpers unless I actually need to input something even if it’s as simple as on or off, that’s what lead to this solution. It also puts everything in one place, which I like (I use packages); YMMV.

My trigger based template select entities are usually dynamic, I don’t know what the options may exactly be so hard coding is out of the question. Using the action select.select_(x) seems to take its reference value from the current state options which will be rerendered when the state resolves on a trigger, if said previous option is no longer valid the state resolves to unknown.

As per the Jinja docs " If you want to use default with variables that evaluate to false you have to set the second parameter to true". My experiments have found that changeing the default second parameter to true is a great catchall. It’ll catch undefined, null, none, false, 0, and "" (empty string).

I think Didgeridrew covered that, multiple entity platforms with multiple entities each.

I’m stupidly appreciative of your work on the Template integration, thank you for all of it.

1 Like

Thanks @petro. Sometimes there’s reasons I just missed or didn’t understand, but just not getting to it yet is also a fine reason. I appreciate the response.

Oh, I had another question probably only you can answer. Why is select_option a required option? It’s possible with optimistic: and triggers to manage the select, so I always wondered why it was a required option.

The parser allows having an empty select_option.

Interesting having the same triggers on multiple platforms. I was just thrown off by having multiple keys because you couldn’t do this, of course:

- triggers:
    - trigger: ...
  binary_sensor:
  sensor:
  binary_sensor:
  sensor:
  ...

because the keys overlap.

I do understand:

 - triggers:
   sensor:
 - sensor:
 - sensor:

Since that’s a list. But they are all separate (and triggers only applies to the first).

And BWT, thanks for the examples. These triggered templates are a real game changer.

You can do your first code block.

That will create those kind of template entities, all triggered by the same triggers defined under triggers
Each domain (binary_sensor, sensor etc) can have it’s own list of entities configured under it, and all of those will be triggered by the same triggers.

Wait, I missed that you were repeating binary_sensor and sensor
You can do:

- triggers:
    - trigger: ...
  binary_sensor:
    - name: binary sensor 1
    - name: binary sensor 2
  sensor:
    - name: sensor 1
    - name: sensor 2
1 Like

But the logic is a bit off, right?

        state: |
          {{ states('sensor.select_entity_reload_value') if trigger.id is eq 'reload' and has_value('sensor.select_entity_reload_value')
              else trigger.event.data.option|default('', true) }}

If trigger.id is “reload” you don’t want to fall back to the “else” that uses the event that contains “option” because that didn’t fire. So something like this instead:

        state: >
          {% if trigger.id == 'reload' %}
            {{
              states('sensor.select_entity_reload_value') if has_value('sensor.select_entity_reload_value')
              else this.attributes.options[0]
            }}
          {% else %}
            {{ trigger.event.data.option }}
          {% endif %}

Why I liked your original post was it got me to spend time digging into the way these templates behave.

And one interesting thing when I was playing with them is that there is sometimes an odd case where the options attributes don’t get set on the entity until a valid state is set.

So, in my code above, IF there’s no valid restore_state entry for the sensor when it first loads, HA reports a list object has no element 0 error:

2026-02-27 05:47:49.804 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: list object has no element 0 when rendering '{% if trigger.id == 'reload' %}
  {{
    states('sensor.select_entity_reload_value') if has_value('sensor.select_entity_reload_value')
    else this.attributes.options[0]
  }}
{% else %}
 {{ trigger.event.data.option }}
{% endif %}'

resulting in the select starting out left as unknown. (At least on my 2026.2.3 test HA in docker.) Minor edge case, of course.

I’m curious if that happens to others, because it’s not consistent so maybe just a timing thing. (In dev tools I can watch the delay in options populating.)

That said, I just went back to my test file from yesterday and I have this tiny select but today when that loads the options show up.

  - select:
      - name: Where are the options?
        options: "{{ [ 'One', 'Two', 'Three' ] }}"
        select_option:

Only on its first initialisation, after that it’s solid.

Same difference I think… because

this is always the previous state object, it can never exist when it first loads. An initial state of unknown is the expected result.

It’s also interesting that a new initialisation of these on an HA restart my example throws a couple of errors, but not when I just use dev tools to reload templates. Either way an error/warning when it first get initialised won’t bother me since it works nicely thereafter.

Although in this case it’s not the select that has a state change.

I think the simpler explanation is that the template isn’t processed until there’s a trigger, and so options just has not been processed yet – or it my be options are async loaded when triggered and just not done populating the attribute when the state template is run and looks for the options, which would be my bet.

I was wondering if adding a unique_id would maybe change that since then the options are written to entity registry, but nope.

Interesting to learn about, but now way down into the minutiae.