CuboMX Release 0.21.0: JSX/TSX Support & Enhanced Event Modifiers
This release brings first-class JSX/TSX support to CuboMX, enabling you to use modern React-like syntax for server-side rendering while maintaining full compatibility with CuboMX's reactive directives. Additionally, we've enhanced event modifiers to work seamlessly with JSX's attribute naming constraints.
✨ New Features
JSX/TSX Support via Preact
CuboMX now supports JSX/TSX for server-side rendering through Preact integration! This allows you to write type-safe, composable components using familiar JSX syntax while leveraging CuboMX's hydration and reactivity.
Installation:
npm install preact preact-render-to-stringConfiguration (tsconfig.json):
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}Example Usage:
import { CuboMX } from "cubomx";
// Define a JSX component
function UserCard({ name, email }: { name: string; email: string }) {
return (
<div mx-data="userCard" className="user-card">
<h2 mx-bind:text="name">{name}</h2>
<p mx-bind:text="email">{email}</p>
</div>
);
}
// Register the component
CuboMX.component("userCard", {
name: null,
email: null,
});
// Swap JSX directly into the DOM
await CuboMX.swap(
<UserCard name="John Doe" email="john@example.com" />,
[{ target: "#container:innerHTML" }]
);
// After hydration, the component becomes reactive
CuboMX.userCard.name = "Jane Smith"; // DOM updates automaticallyWhat's Included:
- VNode Support in
CuboMX.swap(): Theswap()function now accepts both HTML strings and Preact VNodes - New Helper Functions:
isVNode(value)- Type guard to check if a value is a VNoderenderVNodeToString(vnode)- Manually render a VNode to HTML
- Automatic Rendering: VNodes are automatically converted to HTML during swap operations
- Full CuboMX Compatibility: All directives (
mx-data,mx-bind:*,mx-on:*, etc.) work seamlessly in JSX - Type Safety: Full TypeScript support with proper type inference
Benefits:
- ✅ Modern DX with familiar React-like syntax
- ✅ Type-safe component props with TypeScript
- ✅ Composable, reusable components
- ✅ Server-side rendering out of the box
- ✅ Zero breaking changes - fully optional feature
- ✅ Works alongside traditional HTML templates
JSX-Compatible Event Modifier Syntax
Since JSX doesn't allow the @ symbol or dots (.) in attribute names, we've introduced an alternative syntax for event modifiers that's case-insensitive and works across all environments.
New Syntax:
Append the modifier name directly to the event name:
// Traditional HTML/Template syntax (still works)
<form @submit.prevent="save()">
<button @click.stop="handleClick()">
<div @click.outside="close()">
// New JSX/TSX syntax (case-insensitive)
<form mx-on:submitPrevent="save()">
<button mx-on:clickStop="handleClick()">
<div mx-on:clickOutside="close()">How It Works:
The parser intelligently detects modifiers at the end of event names, supporting:
- Dot notation:
click.prevent,submit.stop - camelCase:
clickPrevent,submitStop(JSX) - lowercase:
clickprevent,submitstop(HTML normalized) - ANY CASE:
CLICKPREVENT,ClickPrevent(all work!)
Supported Modifiers:
prevent/.prevent→event.preventDefault()stop/.stop→event.stopPropagation()outside/.outside→ Listen for clicks outside the element
Examples:
// Prevent form submission
<form mx-on:submitPrevent="handleSubmit()">
<button type="submit">Save</button>
</form>
// Stop event propagation
<div mx-on:click="outerClick()">
<button mx-on:clickStop="innerClick()">
Click me
</button>
</div>
// Close on outside click
<div mx-data="dropdown">
<button mx-on:click="toggle()">Toggle</button>
<div mx-show="isOpen" mx-on:clickOutside="close()">
Dropdown content
</div>
</div>All case variations work:
<form mx-on:submitPrevent="save()"> // ✅ camelCase
<form mx-on:submitprevent="save()"> // ✅ lowercase
<form mx-on:SUBMITPREVENT="save()"> // ✅ uppercase
<form mx-on:SubmitPrevent="save()"> // ✅ mixed case🛠️ Improvements
Enhanced Type Definitions
- Updated
PublicAPItype: Theswap()method now acceptsstring | anyto support VNodes without creating a hard dependency on Preact - New exports:
isVNodeandrenderVNodeToStringare now exported from the main module - JSX type support: Full TypeScript support for JSX elements in swap operations
Documentation Updates
- JSX/TSX Installation Guide: Added comprehensive setup instructions in README
- JSX Examples: Updated
CuboMX.swap()documentation with JSX usage examples - Event Modifier Guide: Documented the new JSX-compatible syntax for event modifiers
- Best Practices: Added guidance on when to use JSX vs HTML templates
📦 Technical Details
New Files
src/jsx-helpers.ts- JSX/TSX support utilitiestest/JSX-support.test.tsx- 17 comprehensive tests for JSX functionalitytest/Directive-mx-on-camelCase.test.tsx- 11 tests for case-insensitive event modifiers
Modified Files
src/swap.ts- Added VNode support and automatic renderingsrc/mx-on.ts- Implemented case-insensitive event modifier parsingsrc/cubomx.ts- Exported JSX helper functionssrc/types.ts- Updated type definitions for VNode supporttsconfig.json- Added JSX configurationpackage.json- Added Preact dependenciesREADME.md- Extensive documentation updates
Dependencies
New Dev Dependencies:
preact: ^10.26.1preact-render-to-string: ^6.6.1
Note: These are peer dependencies and completely optional. CuboMX works perfectly without them if you don't use JSX.
📊 Testing
- All existing tests pass: 339 tests total
- 17 new JSX tests: Comprehensive coverage of JSX functionality
- 11 new event modifier tests: Validates case-insensitive parsing
- Zero regressions: Full backward compatibility maintained
🔄 Migration Guide
No migration needed! This release is 100% backward compatible.
If you want to use JSX/TSX:
-
Install dependencies:
npm install preact preact-render-to-string
-
Update
tsconfig.json:{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" } } -
Start using JSX in your
swap()calls:await CuboMX.swap(<MyComponent />, [{ target: "#app" }]);
Event Modifiers:
- Old syntax (
@click.prevent) continues to work - New syntax (
mx-on:clickPrevent) is available for JSX compatibility - Both can be used interchangeably
🎯 What's Next
This release lays the groundwork for modern component-based development with CuboMX. Future releases may explore:
- Enhanced JSX/TSX type definitions
- Additional JSX-specific utilities
- More comprehensive JSX examples and patterns
🙏 Acknowledgments
Thanks to the Preact team for their excellent lightweight React alternative that makes this integration possible!
📝 Full Changelog
Added:
- JSX/TSX support via Preact integration
isVNode()helper functionrenderVNodeToString()helper functionnormalizeToHTMLString()internal utility- Case-insensitive event modifier parsing
- JSX-compatible event modifier syntax (e.g.,
clickPrevent,submitStop) - 28 new tests for JSX and event modifier functionality
- Comprehensive JSX documentation in README
Changed:
CuboMX.swap()now acceptsstring | VNode- Event modifier parsing is now case-insensitive
- Updated TypeScript configuration for JSX support
Fixed:
- Event modifiers now work seamlessly in JSX/TSX environments
Version: 0.21.0
Release Date: November 8, 2025
Total Tests: 339 (all passing)