Custom Components
import { Widget } from 'cx/ui'; Copied CxJS includes many built-in components, but you can create custom ones when needed. Custom components extend base classes like Widget, HtmlElement, Field, or PureContainer.
Example
This example creates a Square component with bindable color properties. Click the square to set a random color.
Square.tsx - The widget class (uses React JSX):
/** @jsxImportSource react */
import { RenderingContext, Instance, Widget } from "cx/ui";
import type { NumberProp, WidgetConfig } from "cx/ui";
export interface SquareConfig extends WidgetConfig {
red?: NumberProp;
green?: NumberProp;
blue?: NumberProp;
}
export class Square extends Widget<SquareConfig> {
declare red: number;
declare green: number;
declare blue: number;
declareData(...args: Record<string, any>[]) {
super.declareData(...args, {
red: undefined,
green: undefined,
blue: undefined,
});
}
setRandomColor(instance: Instance) {
instance.set("red", Math.floor(Math.random() * 256));
instance.set("green", Math.floor(Math.random() * 256));
instance.set("blue", Math.floor(Math.random() * 256));
}
render(context: RenderingContext, instance: Instance, key: string) {
const { data } = instance;
return (
<div
key={key}
style={{
width: 100,
height: 100,
backgroundColor: `rgb(${data.red}, ${data.green}, ${data.blue})`,
cursor: "pointer",
borderRadius: 4,
}}
onClick={() => this.setRandomColor(instance)}
/>
);
}
}
Square.prototype.red = 0;
Square.prototype.green = 0;
Square.prototype.blue = 0;
Usage - CxJS application code:
<div class="flex gap-8 items-center">
<LabelsLeftLayout>
<Slider label="Red" value={bind(m.red, 0)} minValue={0} maxValue={255} />
<Slider
label="Green"
value={bind(m.green, 0)}
minValue={0}
maxValue={255}
/>
<Slider label="Blue" value={bind(m.blue, 0)} minValue={0} maxValue={255} />
</LabelsLeftLayout>
<Square red={m.red} green={m.green} blue={m.blue} />
</div> React JSX Pragma
Widget files must use the React JSX pragma because the render method returns React elements:
/** @jsxImportSource react */
Config Interface
Define a config interface for your component’s properties. Use prop types like StringProp, NumberProp, BooleanProp for bindable properties:
interface SquareConfig extends WidgetConfig {
red?: NumberProp;
green?: NumberProp;
blue?: NumberProp;
}
Widget Class
Extend Widget (or another base class) with your config type. Use declare for properties to avoid overwriting config values:
class Square extends Widget<SquareConfig> {
declare red: number;
declare green: number;
declare blue: number;
}
Widget Methods
declareData
Register bindable properties. Properties declared here can use data binding:
declareData(...args) {
super.declareData(...args, {
red: undefined,
green: undefined,
blue: undefined,
});
}
Use { structured: true } for object properties with bindable sub-properties.
render
Returns React elements for the component’s visual representation:
render(context: RenderingContext, instance: Instance, key: string) {
const { data } = instance;
return (
<div key={key} style={{ backgroundColor: `rgb(${data.red}, ${data.green}, ${data.blue})` }} />
);
}
Parameters:
context- Passes information between parent and child widgetsinstance- Containsdata,store, and instance-specific propertieskey- Unique identifier for React reconciliation
init
Called once when the widget class is initialized, before any rendering.
initInstance
Called for each widget instance. Use this to set up instance-specific data:
initInstance(context: RenderingContext, instance: Instance) {
instance.customData = {};
super.initInstance(context, instance);
}
initState
Sets the initial internal state for stateful components.
explore
Evaluates data-bound attributes and explores children. Called before prepare:
explore(context: RenderingContext, instance: Instance) {
super.explore(context, instance);
// Access instance.data here
}
prepare
Additional preparation after explore, before render. Use to get information from context.
cleanup
Called after rendering to perform cleanup work.
Prototype Defaults
Set default property values on the prototype:
Square.prototype.red = 0;
Square.prototype.green = 0;
Square.prototype.blue = 0;
Base Classes
| Base Class | Use Case |
|---|---|
Widget | Basic widgets |
HtmlElement | Widgets rendering HTML elements with styling support |
Field | Form input widgets with validation |
PureContainer | Containers without HTML wrapper |
Container | Containers with HTML wrapper |