# Why TSRX isn't just your Favorite Templating Language You may have heard some talk recently about a potential JSX sucessor, [TSRX](https://tsrx.dev/), created by Dominic Gannaway([@trueadm](https://x.com/trueadm)) the creator of Inferno & Ripple, and former React and Svelte core team member. It is available today as an Alpha for React, SolidJS, and Ripple. I’m going to preface this by saying this isn’t an area I’ve considered that important. It’s why SolidJS hasn't explored this. It’s why I never felt compelled, even in the slightest, to go in the direction of Vue or Svelte. Why, at times, I even refer to people who die on this hill as missing the plot. That getting sucked into such superficialities masks a lack of critical thinking and understanding. And yet I’ve written on this topic several times over the years. Talked about [ReactiveScript](https://dev.to/playfulprogramming/the-quest-for-reactivescript-3ka3) and [again](/dYI4i1mXQ12T9B4ZzkEQ6Q) (I might even still hold reactivescript.dev), talked about [A True Successor to JSX](/J6ySbWguTuS_g626Y66WKQ). I've done several streams on it too. Why? Mechanics. The same reason I’ve always held JSX in high esteem. Not because of some preferential feeling it gives me. But it is mechanically powerful in its flexibility compared to more constrained template DSLs. I don’t care how many characters you need to type. That’s for misers, and armchair critics, people who act like they know what they are talking about. I care what the language design is capable of. For example, JSX is portable in the sense that you can move it around, assign it to a variable, use it as a prop, etc… That is actually something. When working [Marko 6 Tags API](https://dev.to/ryansolid/marko-designing-a-ui-language-2hni), I realized we were really on to something. And while I came to a realization many people would never accept Marko, even if it is the tersest UI language you’ll ever come across, mechanically it was capable of something no other templating language did so natively. I called it WYSIWYG templating. Maybe I should just call it stateful templating. And as it turns out, TSRX has the same properties. Does that mean I think everyone will/should accept TSRX? No, that’s not up to me. Does it mean it is interesting? Very much so. ## Static Analyzable Structuring Let’s start with what many templating languages have. They have some means to inject control flow. Loops, conditionals that can be “seen” in the templating language. Examples of this are `v-if`/`v-for` attribute, `{#if}` mustache inspired escape blocks, `? :`/`&&` ternary/boolean operators, designated elements `<for>`. Know what isn’t? `something.map(() => {})`. This is a method call on an object that could mean anything. `.map` in RxJS, for example, is not the same as `.map` on an array. That being said, JSX generally isn’t considered to have static analyzable structuring. Dominic(creator of TSRX) and I proved differently years ago with our projects Inferno, and SolidJS, respectively, but we didn’t do so by analyzing control flow, just template shape. How to leverage the holes versus the static blocks. Solid’s `<For>` is actually just a normal component. It calls a special `map` function inside. No special compiler magic. So that is an example of the mechanical advantage of many non-JSX DSLs. The tradeoff is that it often isn’t composable on identity. What I mean is, in user space, you can’t make your own `#each` with the exact same syntax. Which is arguably a JSX super power. Everything is just a component. The only system that is cleanly both is arguably Marko (since everything is a tag and it has reserved compiler tags). But we aren’t talking about Marko today, and composability at the cost of explicitness might be overrated in some cases. I still think composability is king, but loosening that puts you in the same category as Vue/Svelte, etc., and is what TSRX’s use of `if` and `for` is doing. The nicety is because of not making it expression based and using statements instead, you can use plain JavaScript conditionals/loops. This does suggest that, unlike JSX, it isn’t returning things. And that is a bit of a tension for sure. There is a `<tsx>` escape hatch though. But the right way to think about this is that this is basically Single File Component-like semantics inside a `component` function scope. And now because of `component` those scopes are known. Great for HMR, great for any sort of localized optimization, ergonomic (ex. safe reactive destructure) or performance. TSRX answers the question of what if I want the same mechanical capability of Vue/Svelte, but the syntax of JavaScript. What is the JavaScript doing? Providing a scoping mechanism in a way HTML toplevel can’t really compare. ## Stateful Templates Why does it matter? That alone would sway me very little. After all, isn’t that just Vue/Svelte with a different syntax? Mostly. I could argue that the component functions add a bit more portability. The use of JavaScript as the control flow DSL is less concepts (what is mustache, why are there special attributes). But explaining how things don’t return is very much not JavaScript and pretty much makes that a wash in my mind. So again, why would I care? And this is probably the hardest thing for both React devs and people pulling out their Liquid server templates. Templates don’t need to be re-run over and over and over again. In a world that recreates everything over and over, control flow analysis is meaningless. Not meaningless, but it is an optimization. React Compiler looks at that. But the latest crop of UI frameworks based on Fine-grained rendering actually benefits from structural optimization. Does it need to happen in the compiler? No. Not at all. But when component lifecycles don’t matter, nothing is a “component,” and everything is a “component”. When only what needs to re-render does so, state can live anywhere safely. It can be at the top, passed through 20 components at no cost, or it can be as close to where you are doing the work as needed, inside each loop iteration. Components don’t matter mechanically. Decoupling components from state also means that the `component` keyword takes on a different meaning. It is just identifying where the template starts. Nothing to do with lifecycle necessarily. I’m going to reuse an example from Marko's article. Consider this wrapper: ```js // jsx function Chart({ data }) { let ref; useEffect(() => { const chart = new Chart(ref, data); return () => chart.dispose(); }, [data]) return <div ref={ref} /> } // tsrx component Chart({ data }) { let ref; useEffect(() => { const chart = new Chart(ref, data); return () => chart.dispose(); }, [data]) <div ref={ref} /> } ``` Now we add a new conditional visibility prop: ```jsx // jsx function Chart({ data, enabled }) { let ref; useEffect(() => { const chart = enabled ? new Chart(ref, data) : null; return () => chart?.dispose(); }, [data, enabled]) return enabled && <div ref={ref} /> } // tsrx component Chart({ data, enabled }) { if (enabled) { let ref; useEffect(() => { const chart = new Chart(ref, data); return () => chart.dispose(); }, [data]) <div ref={ref} /> } } ``` How many places in the code did we change? In TSRX, we added one conditional and indented the block. In JSX, we added `enabled` in 3 places, and made the disposal conditional. This is with a single simple effect and element. What if you do this work and decide it is better to just extract it to another component again? With TSRX, I just cut and paste. With JSX, I would need to undo that work. Now the savvy React dev will be like, wait a second, you can’t put hooks in conditionals. What if you could? That’s what is offered here and what’s always been the case in Signals libraries. They can, they don’t have hook rules. But the templating doesn’t always make it easy. SolidJS’s control flows are optionally render props, so we could: ```jsx function Chart(props) { return <Show when={props.enabled}>{ (enabled) => { let ref; createEffect(() => { const chart = new Chart(ref, data); onCleanup(chart.dispose); }) return <div ref={ref} /> } }</Show> } ``` But would you? This has the same cut/pastability with no code change. But it is bulky. You might take this as a hint on what is a good candidate for new Components/Svelte style snippets but organically being able to build your UI in place is nice. A true test of composability is whether there is no difference between building something in one scope or a dozen. I’ve used that bar myself a lot because it is a true testament to how much is actually in the developers' hands. ## Conclusion I hope by looking at this now, you can at least see why, even if you want to argue about syntax choices, there is a mechanical capability worth talking about. Those deep in Vue/Svelte might shrug this off as we’ve been doing this the whole time, but do you have optionally portable stateful templates? This almost furthens the gap from traditional SFCs(Single File Components). This might not be for you anyway because it is likely you prioritized different non-mechanical things in the first place. For React developers, this is interesting because it can remove some of the tediousness of Hook rules and unlock some of the potential Signals libraries have been getting for free for years. Does it change enough for you? Or have you already checked out because you use the most popular solution? I don’t know. For Solid developers, this looks like the templating language you may have always wanted, but does it go against the transparency the framework has fought so hard to keep? Maybe you don’t care as much as I do? Maybe there are some important learnings here. Maybe this becomes super popular within our ecosystem since it is the perfect Venn diagram complement. What about [Mitosis](https://mitosis.builder.io/)? If you remember, I was involved a bit with the project at its inception stage (JSX-lite). This is very different as it isn’t about writing something familiar (ie bastardized React with Solid like semantics) to generate any frameworks code. But trying to provide a syntax that people want to use. There are component libraries built purely on Mitosis that work in all the frameworks. That is one angle here for TSRX, but staying within the existing framework's own lanes is perfectly viable, which makes this different. I think between the mechanical capabilities. The impact AI is having on how we build. The differences between this and say Mitosis put it in a new space. This is a fundamentally different solution in a fundamentally different time. And if nothing else, we should be conscious of that.