I started with a templating system that had a very limited logic and I'm still quite fond of this approach.
Basically arguments for a template had a form of a tree prepared by the controller function. The template could only display values from the tree (possibly processed by some library function, for example date formatter), hide or show fragments of html dependaning on the presence or absence of some value or branch in the tree, descend into a branch of a tree and iterate over an array from the tree, while descending into one iteration at a time. Also could include subtemplate feeding it a branch of the tree. This was enough to build any UI out of components and kept their html simple, separate and 100% html. Even the template logic had a form of html comments. One could open such template in any html editor including visual ones. It was all before advent of client side frameworks.
You could mimic this in React by preparing all data in render method as a jsonlike tree before outputting any JSX tag and limit yourself inside JSX part to just if and map(it =>{}) and single value {}