You will find both of @m-gallesio’s suggestion works. What does not work is that they don’t create the real id attribute on the input element itself. That’s what you tried to see when inspecting the element.
The reason is you provided a custom attribute on a standard attribute called id, which took over the default Aurelia behaviour.
Solution: remove your custom attribute implementation, let Aurelia to do its work. You will see Aurelia will populate the real id attribute with both suggestions from @m-gallesio.
I removed the id custom attribute ES class, and it works now. Thanks!
However it was just a first step. If I replace the id attribute in the HTML template with a test-id attribute without a matching view model class, I can notice:
The test-id is rendered if its value is static (ex.: test-id=“foo”).
The test-id is missing if its value needs a string interpolation (ex.: test-id=“foo-${$index}”).
If you provide a custom attribute implementation, aurelia assumes you will play the value in your code.
It does not rewrite html attribute back to the node for most use cases.
Aurelia does write back attribute to the node on some special attributes. For example, id. This is designed to play nice with other 3rd party js lib which wants the real attribute on the node.
The other special attributes you can use are data- and aria- attributes. If you bind to data-id, aurelia will populate the attribute for you. This is also designed to play nice to other js libs. For example, bootstrap uses data- attributes as parameters of many features.
Again, don’t provide a custom attribute implementation for data-id.