JSX Syntax
CxJS uses JSX to define user interfaces declaratively. If you’re familiar with React, you’ll find the syntax familiar — with some CxJS-specific extensions.
Widgets vs HTML Elements
CxJS follows a simple naming convention — widgets start with an uppercase letter (Button, TextField, Grid) while HTML elements start with a lowercase letter (div, span, section). You can freely mix them in the same component.
CxJS widgets also support common attributes for controlling behavior and appearance. Use visible to conditionally render widgets, class or className for CSS classes, and style for inline styles:
<div class="flex flex-col gap-4">
<div class="p-4 border border-border rounded">
<strong>Mixing Widgets and HTML</strong>
<div class="flex gap-2 items-center mt-2">
<TextField value={m.name} placeholder="Your name" />
<Button>Greet</Button>
</div>
</div>
<div class="p-4 border border-border rounded min-h-24">
<strong>Visibility Control</strong>
<div class="mt-2">
<Switch value={m.showMessage}>Show message</Switch>
</div>
<div visible={m.showMessage} class="mt-2 text-primary">
This text is conditionally visible!
</div>
</div>
</div> The <cx> Wrapper
In earlier versions of CxJS, widget trees had to be wrapped in a <cx> element to instruct
the Babel compiler to process them as CxJS configuration. With TypeScript and the new
jsxImportSource: "cx" configuration, this wrapper is no longer required:
<div class="flex gap-2 p-4">
<TextField value={m.name} placeholder="Your name" />
<Button>Submit</Button>
</div> The legacy <cx> syntax is still supported for backwards compatibility:
<cx>
<div class="flex gap-2 p-4">
<TextField value={m.name} placeholder="Your name" />
<Button>Submit</Button>
</div>
</cx> Key Differences from React
| Feature | React | CxJS |
|---|---|---|
| Class names | className only | class or className |
| Two-way binding | Manual | Built-in via accessor chains |
| State management | useState, Redux | Store with typed models |
| Component wrapper | None | <cx> (optional) |