The problem with forms is that they combine presentation with business logic. In any decent architecture, your UI has no business directly encoding API requests and directly submitting them to the server.
But of course, this was necessary in the early "thin client" days of HTML, before we had a well-developed client-side platform to encode client-side concerns independently of their presentation.
Case in point I rarely use <form> elements at all in my applications. I use form controls, of course. But all form data is collected, transformed in a FormData instance and sent via XHR. This is infinitely better and provides great opportunities for UI component reuse independent of what your server-side API shape happens to be. It also means no more "hidden inputs". Which is non-sense if you think about it. If the user can't edit it, or even just see it, what is it doing in the HTML form? Again, in the 90s it made sense. In 2020 it makes no sense.
HTML today is UI even more than it ever was. That's good. And UI is a tree, because it's a visual hierarchy. And that's all your need. HTML is not your entire application. And the rest of your application is already a graph.
But the for attribute now gives us the best of both worlds. I still use form tags, but always make them close immediately are style them to not display. This preserves functionality without JS while also separating business logic and display.
EDIT: I don't know why you're being downvoted, I get what you're saying. For example encoding the form URL in the HTML is a violation of separating business logic and display since you may want the submittal link to be dynamic based on the values in the form, and using JS to update the form action attribute doesn't really solve anything, but I feel like using for is a pragmatic compromise between the reality and history of HTML and a more ideal architecture.
HTML has a few kludges here and there that seem questionable on close inspection. Sure, having the "id" attribute and then referring to this id from anywhere else allows you to build an arbitrary directed graph of relationships independent of the DOM tree.
And that's useful in CSS selectors and from JS and so on.
Within HTML itself, the "for" attribute on a label has two behaviors... One is to read out the label for a given input for visually impaired users, and the other is to focus the input when you click the label.
The focus behavior is kinda useless, most people click the input, not the label. But OK, it's harmless, and nice to have. The accessibility feature makes more sense but also highlights the fact that a control and its label are intrinsically one unit. And in many UI frameworks they are one unit.
So why aren't they in HTML? Because INPUT existed in HTML far before accessibility was a concern, and people were writing out labels outside the inputs. So later versions of HTML had to deal with the status quo, and added LABEL to "patch" the problem without disrupting the existing form control behavior.
So this particular case is a historical quirk. Would HTML be redesigned, the label would be in the input, and you'd probably be styling it with a pseudo-selector, like you do :placeholder etc.
But of course, this was necessary in the early "thin client" days of HTML, before we had a well-developed client-side platform to encode client-side concerns independently of their presentation.
Case in point I rarely use <form> elements at all in my applications. I use form controls, of course. But all form data is collected, transformed in a FormData instance and sent via XHR. This is infinitely better and provides great opportunities for UI component reuse independent of what your server-side API shape happens to be. It also means no more "hidden inputs". Which is non-sense if you think about it. If the user can't edit it, or even just see it, what is it doing in the HTML form? Again, in the 90s it made sense. In 2020 it makes no sense.
HTML today is UI even more than it ever was. That's good. And UI is a tree, because it's a visual hierarchy. And that's all your need. HTML is not your entire application. And the rest of your application is already a graph.