The primary restriction is that your output can be modelled as a tree in some way, and what you find is that nearly everything falls into this category. I don't know if anyone's done it yet, but a plain-text renderer is certainly possible, I imagine it would be very similar to a terminal renderer.
(This is also why "templating languages" in PHP were a special kind of foolish; PHP is a templating language.)
Any PHP project of any reasonable complexity will either use an existing "templating language" (by which you probably mean a framework) or be forced to create some sloppy, ad-hoc version of one, because while yes, PHP is a templating language/framework, it's also a terrible one.
JSX is a data structure with a syntax similar to XML. The angle brackets are quite similar to brackets around any other data structural literal in any other syntax.
The tag names are references to either in-scope variables/constants (when capitalized), or references to a static set of HTML element names specified by React (when lowercase). This is different from HTML or even XML because they are evaluated at runtime (plain JSX->JS compilation) or validated at compile time (e.g. TypeScript).
The attributes names are keys in the data structure's props, and the values are either static (if specified as string literals) or dynamic (if specified between curly braces). These too can be checked at runtime (with PropTypes) or at compile time (e.g. TypeScript).
By specifying dynamic props (or conditional children), the component will re-render as the values change.
I'm not aware of any other HTML-like or XML-like template language which functions the same way.
Edit: I forgot to mention, dynamic props are also exactly JavaScript/JSX expressions. Basically JSX is a macro that turns the XML-like stuff into React API calls.