Yeah, I agree, I find them hard to read. JSX is the best thing I've used. Elsewhere in the thread someone mentioned Cotton which seems to strike a different balance.
To be honest my main problem with templates is they have to be one per file. In principle there's no difference between naming a new file and naming a function, but in practice it just sucks. It's a higher barrier so people are less likely to write smaller components, and refactoring support completely sucks. Even renaming a template is a massive pain whereas renaming a function with decent LSP support is easy.
JSX hits that perfect balance between readability while still being regular functions. Maybe something is possible with the new 3.13 template strings?
As an FYI, I'm with the template strings folks (new feature in 3.14) and we're building an HTML system around the idea of JSX-style components as callables, but with actual strings of HTML. Check our <a href="https://t-strings.github.io/tdom/usage/components.html">components page</a> for more detail.
With template strings, the symbols in the HTML string a just like Python code. Static analysis tooling can step in and do things.
We have ambitions to start an interoperability movement in Python HTML, so htpy and tdom could agree on a common Node structure.
The downside is I find them hard to read.
I think the template approach isn't quite right and yet neither is the functional approach.
At the end of the day these are a type of tree structure; I think we could conjure a new mechanism that gets the best of most/both worlds.