Feature Request: Native support for JSX like syntax #2051
Replies: 12 comments
-
Can you recommend further reading that does a deeper detailed dive into the design of JSX for people who have tried React in the past and were turned off by the inclusion of JSX into the JavaScript source code?
|
Beta Was this translation helpful? Give feedback.
-
@gmlewis I am the author of SolidJS: The Complete Guide, where I have explored various aspects and benefits of JSX across multiple chapters. However, the discussion is spread throughout the book rather than being confined to a single section. Relevant chapters include:
Yeah, class-based components were confusing, and they’ve pretty much gone extinct now. Function components are much better—they simplify UI logic and eliminate unnecessary complexity. Solid’s JSX implementation takes this even further by removing extra clutter and providing a cleaner, more straightforward abstraction. In the early days, many developers assumed JSX was just another templating language, and some were put off because it gave them PHP-like vibes. But JSX is nothing like PHP, and it doesn’t enforce a particular output. Unlike traditional MVC frameworks that tightly coupled templates with controllers, JSX’s declarative composition model made many of those approaches obsolete. JSX is now ubiquitous, supported natively by modern runtimes, compilers, and frameworks beyond React. Solid, Preact, Vue (via plugins), and even Deno recognize it as a first-class syntax. With TypeScript, Babel, SWC, and ESBuild optimizing its transformation, JSX has moved beyond being a React-specific feature to a universal tool for declarative UI development. The understanding I have amassed comes from years of working with different frameworks that utilize JSX, as well as various conference talks and discussions that predate the widespread adoption of React. I apologize for not being able to provide direct content from my book, as the platform I use for selling it doesn’t support giveaways. However, if you’re interested, I’d be happy to email you a copy. Alternatively, you can purchase it here: https://solid.courses/p/solidjs-the-complete-guide/ Unfortunately, a lot of the deeper discussions on JSX have been buried under basic tutorials. There isn’t really one definitive resource that covers everything, but here are some links that discuss JSX’s philosophy and composition model in more detail. They might help, but they certainly fall short of showcasing the true power of JSX: |
Beta Was this translation helpful? Give feedback.
-
However, Moonbit's goal is designed as a cross-platform language. Although it could target JavaScript/WASM, it also supports C and LLVM. To my knowledge, MoonBit has plans to support additional backends in the future. I'm concerned that introducing native support for JSX might pose significant challenges for other non-JavaScript backends. |
Beta Was this translation helpful? Give feedback.
-
Ah, perfect! That's exactly the kind of thing that I was looking for. Thank you, @snnsnn! (And congratulations on the book!) |
Beta Was this translation helpful? Give feedback.
-
@Kaida-Amethyst Sorry, my intent was lost during rewrites as the text evolved, making it seem like I was asking for JSX support. However, that is not the case. I am not requesting JSX support but rather a syntax without fixed semantics that allows composition—akin to JSX—yet something even more powerful. A clear, concise, and universally accepted way to describe intent. To clarify my request, I have revised the earlier text into three sections:
I hope this helps clear up any confusion and more accurately conveys my intent. |
Beta Was this translation helpful? Give feedback.
-
@gmlewis Exactly! JSX is the greatest innovation since HTML/XML, yet it surpasses both. I believe React’s convoluted execution logic and arbitrary rules have overshadowed its true potential. Since JSX lacks fixed semantics and can be transformed into different representations, it naturally enables cross-platform usage. Each platform can define its own type system for strong type support, tailoring JSX’s interpretation to its needs. The best part is that the developer defines the types and their meaning.
Thank you! There’s more to come, as I’m currently working on two more chapters: Solid Router and SolidStart. |
Beta Was this translation helpful? Give feedback.
-
Are you proposing a macro system in Moonbit, similar to Rust macro or Lisp macro, but utilizing a JSX-like syntax? |
Beta Was this translation helpful? Give feedback.
-
I see you have not worked with jsx before. No, not a macro system but a native syntax support. With macros, what you write is text, and you fit your DSL into the language. Let's use an example from the rust language that imitates jsx like behavior using a macro: let node: DOMNode = rsx! {
<view style={stylesheet.take(".root")}>
<image style={stylesheet.take(".image")} src="..." />
<text style={stylesheet.take(".text")}>
Hello world!
</text>
</view>
}; Basically, you write text. It is not universal. It is not any different from a templating language. But with JSX like syntax, you don't use text, but a proper HTML like syntax that provides strong type support, composition and reuse: const body = (
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/public/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Title</title>
<link rel="stylesheet" href="/public/style.css" />
</head>
<body>
<h1>Home</h1>
<Button type="primary" size="medium">Click here</Button>
<script src="/public/reload.js"></script>
</body>
</html>
); Here, what Hero returns will be placed in our page: function Button({
type,
size,
children
}: {
type: "primary" | "secondary",
size: "small" | "medium" | "large",
children: JSX.Element
}) {
return (
<button class={[size, type]}>{children}</button>
);
} Our Unlike a macro, a JSX node produce a proper AST node: But you let the developer transform these AST representations into proper language code by allowing him to plug into the compilation process. In the DOM, this can create an HTML document, but on the server, it may create a string that could be sent to the client. With native syntax, you enjoy all the benefits of a statically typed language: static analysis, strong type support, linting, etc. What I am asking for is native syntax support with a way to plug into the compilation process and transform the intermediate representation of the AST into the final code that will be executed by the platform or the runtime. You can take a look at these resources for further information:
Deno and ReScript allow only limited transformation capabilities. With a Babel plugin—not |
Beta Was this translation helpful? Give feedback.
-
We are aware of the request. We'll evaluate the necessity during the development of rabbit-tea and other packages. |
Beta Was this translation helpful? Give feedback.
-
https://github.com/oboard/mbx-compiler a moonbit xml example with rabbit-tea |
Beta Was this translation helpful? Give feedback.
-
JSX adds support for tree-like composition using a declarative syntax, it's very hard to move to languages without a declarative tree syntax, some UI frameworks like kotlin's jetpack compose even came up with it's own DSL for tree like composition inspired by JSX |
Beta Was this translation helpful? Give feedback.
-
The creator of Moonbit @bobzhang also created another language with JSX support called Rescript while working at facebook |
Beta Was this translation helpful? Give feedback.
-
MoonBit is an exciting new language with a focus on performance, safety, and modern development patterns. However, one crucial feature that could significantly enhance its capabilities—especially for web and UI development—is native JSX like syntax. Not JSX, but JSX like. Let me elaborate on the characteristics of such a syntax:
Syntax with No Fixed Semantics
This means the code is always transformed, and what is produced is dictated by the consumer. Having no fixed semantics means that
<div title="some title">Some Content</div>
has no inherent meaning; its meaning depends entirely on the developer’s code processing this data. It could be a DOM element—not necessarily a<div>
but any DOM element—or it could be a string representing a partial HTML snippet for a<div>
element. It could be anything. All we can say is that<div title="some title">Some Content</div>
describes our intent, but what it produces is entirely up to the developer. On the server side, our code might become one thing; on the client side, another; and on mobile platforms or in VR, something else entirely. The syntax provides a clear and concise way to describe our intent, while the semantics are left to the developer or the platform consuming this data.Modern JSX achieves this in different ways. The most common approach is allowing developers to import their own functions that transform JSX code into arbitrary code dynamically at runtime. However, there is a better approach: allowing developers to tap into the compilation process and process data statically. This approach is far more powerful and flexible, providing all the benefits offered by the language compiler, including strong type checking, linting, type inference, and IntelliSense.
Composable
JSX shares the same characteristics as HTML: you can compose smaller parts into larger ones. It is better than HTML because you can use functions to express your intent. It is better than function composition alone because the syntax is clear and concise, and the ability to inline expressions provides additional power. In a way, it combines HTML + function composition + expressions.
It is better than function composition because function composition alone cannot achieve the same level of clarity and conciseness. It is better than HTML because HTML alone cannot achieve the same level of flexibility. Function components provide both abstraction and co-location.
A Universal Way To Describe Intent
The syntax defines the rules but not the semantics. This makes it a universal language for expressing intent, and it aligns perfectly with the trait system. JSX is a specification—a common set of rules for writing this syntax. Implementing the JSX specification directly may not be a good fit for Moonbit, as it has its own type system, but Moonbit could develop its own specification, drawing from the JSX experience.
Here, I specifically refrained from using the word UI and instead chose intent, avoid the common misconception that JSX is strictly tied to rendering interfaces, as it better captures the functionality offered by JSX-like syntax. When we say UI, the meaning may be restricted to user interfaces, but JSX-like syntax is not limited to that. It could represent any viewport or even serve as a single source of truth for producing cross platform code.
I want to emphasize that I am advocating for a JSX-like syntax—a general-purpose declarative representation where the semantics are determined by the consumer. If possible, this should be achieved at the compiler level.
Other Benefits
All the other features—declarative, scalable, maintainable, reusable, flexible, and concise code—are natural outcomes of these two fundamental characteristics.
I did not include examples because I know that you, as the language designers, are already familiar with JSX, having implemented it for ReScript.
General Information on JSX
JSX is more than just a syntax; it provides a powerful declarative composition model that makes building and structuring UI components much more intuitive.
JSX has been a somewhat contentious topic. Some see it as an unnecessary abstraction, while others recognize its power in structuring UI in a declarative and composable way. However, the discussion should not be about JSX as it exists in JavaScript, but rather about something like JSX—a syntax with fixed rules but no fixed semantics.
A key reason JSX is so effective is that semantics is not tied to syntax. Unlike traditional UI markup languages like HTML or XML, JSX doesn’t enforce a specific meaning on its syntax. Instead, it allows the underlying system to define what JSX expressions mean, making it a versatile abstraction for any component-based system, including MoonBit.
By providing a JSX like syntax, MoonBit could unlock a new level of expressiveness, reusability, and developer experience, making it a compelling choice for frontend and full-stack development.
The Power of JSX’s Composition Model
Declarative and Readable UI Structure
One of the fundamental advantages of JSX is its declarative nature. Instead of imperatively constructing elements step by step, JSX describes what the UI should look like, leaving the underlying system to handle how it gets created. This reduces cognitive load—developers focus on what the UI should be, not how to construct it. It maps more naturally to component-based architectures.
Semantics Is Not Tied to Syntax
One of JSX’s most misunderstood yet powerful features is that it does not dictate what elements mean. Unlike HTML, where
<div>
,<p>
, and<button>
have predefined browser behaviors, JSX doesn’t enforce any specific semantics on elements. The meaning is determined entirely by how the JSX is transformed by the underlying system. This flexibility allows JSX to be used beyond the DOM, making it an ideal abstraction for any UI system, including MoonBit’s runtime.JSX provides an abstraction layer where imported modules can define their own meaning for UI elements. This makes it suitable for defining a universal UI language, while the inner workings can be library-specific. Once again, JSX is not a DSL—it consists of syntax rules that are not tied to specific semantics.
In short, JSX is not "HTML in JavaScript"—it’s a flexible syntax for composing declarative structures. This separation of semantics from syntax is what makes JSX so extensible and why MoonBit should leverage it.
Encapsulation and Reusability
JSX makes it incredibly easy to define and reuse components without needing complex factory functions or manual object instantiation. This improves maintainability and modularity in large codebases.
Composable UI Patterns: Composition Over Inheritance
JSX allows components to be composed like natural building blocks. Instead of handling UI structure through nested function calls, JSX encourages hierarchical and declarative composition.
JSX’s design is inherently composition-first, which aligns with modern best practices in software architecture. Instead of relying on inheritance-based hierarchies, JSX allows smaller, reusable components to be dynamically composed together. This makes it a natural fit for languages that embrace traits instead of class-based inheritance—like MoonBit.
JSX’s composition model naturally enables Higher-Order Components (HOCs), which are similar to trait-based decorators. Instead of subclassing, a component can wrap another component to extend its behavior.
The Case for Composition, Traits, and JSX in MoonBit
Many people unfamiliar with JSX may mistakenly associate it with JavaScript or assume it is just another Domain-Specific Language (DSL) for UI development. However, JSX is not JavaScript, nor is it a traditional DSL—it is something far more flexible and powerful. Unlike a DSL, which is typically rigid and tailored for a specific purpose, JSX is almost infinitely adaptable because its semantics are not predefined. It is merely a syntactic construct that can be interpreted in any way the underlying system defines. Whether used to generate virtual DOM nodes, compile to highly optimized data structures, interact with native UI frameworks, or even serve as a template for entirely different domains, JSX adapts seamlessly to its environment. This flexibility makes it an ideal choice for MoonBit, allowing UI libraries to define their own rendering logic while keeping a clean, declarative, and composable syntax. JSX is not a language—it is a universal abstraction for structured composition.
The advantages of JSX go beyond just convenience—they represent a fundamental improvement in how UI logic is structured and managed. By leveraging JSX’s declarative syntax and composition model, MoonBit can establish a more scalable, maintainable, and expressive UI development paradigm. Unlike traditional inheritance-based UI architectures, which become brittle as complexity grows, JSX promotes modularity, flexibility, and reusability—all essential for building robust applications. Here’s why MoonBit stands to benefit:
Separation of Concerns:
Flexibility & Scalability:
Reusability:
More Natural for Functional and Declarative UI Development:
Conclusion
What I am advocating for is native support for JSX-like syntax in MoonBit, not as a DSL with rigid behavior, but as a flexible, structured composition model that seamlessly integrates with MoonBit’s type system and traits. JSX is not tied to the DOM; its purpose is to compose the UI layer in a declarative way, regardless of how that UI is rendered. Whether used for server-rendered output, native UI components, static HTML generation, or even compiling to optimized data structures, JSX-like syntax remains a universal way to express UI composition.
By embracing this approach, MoonBit can provide a modern, scalable, and reusable UI development experience without compromising performance or flexibility.
With JSX and traits combined, MoonBit can leverage the best of declarative UI programming while maintaining type safety and flexibility.
I appreciate your time and consideration in discussing this proposal. Looking forward to hearing your thoughts and insights.
Regards.
Beta Was this translation helpful? Give feedback.
All reactions