Radiant Counter
The smallest example comparing the two main RadiantElement host modes.
Live Comparison
JSX-Owned Host
RadiantElement Host
Live Example: JSX-Owned RadiantElement
The live demo renders the custom element directly, so the server HTML comes from the RadiantElement host itself rather than from a wrapper component.
It demonstrates:
- a public
@prop(...)for the element API - host-owned JSX through
render() - SSR coming from the custom element host via
renderComponent(...)/ the server pipeline - event handling with
on:click - no imperative DOM syncing step for the counter text
import { RadiantElement, customElement, prop } from '@ecopages/radiant';
export type RadiantCounterProps = {
value?: number;
};
@customElement('radiant-counter')
export class RadiantCounter extends RadiantElement<RadiantCounterProps> {
@prop({ type: Number, reflect: true }) value = 0;
private readonly decrement = () => {
if (this.value > 0) {
this.value -= 1;
}
};
private readonly increment = () => {
this.value += 1;
};
override render() {
return (
<>
<button type="button" on:click={this.decrement} aria-label="Decrement">
-
</button>
<span>{this.$.value}</span>
<button type="button" on:click={this.increment} aria-label="Increment">
+
</button>
</>
);
}
}The Same Behavior With Authored Light DOM
RadiantElement does not own the view — the HTML is authored or server-rendered, and the component enhances it with behavior.
<counter-element value="5">
<button type="button" data-ref="decrement" aria-label="Decrement">-</button>
<span data-ref="count">5</span>
<button type="button" data-ref="increment" aria-label="Increment">+</button>
</counter-element>The script attaches to existing markup using data-ref queries and decorator-driven event listeners.
import { RadiantElement, customElement, onEvent, onUpdated, prop, query } from '@ecopages/radiant';
@customElement('counter-element')
export class CounterElement extends RadiantElement {
@prop({ type: Number, reflect: true, defaultValue: 0 }) declare value: number;
@query({ ref: 'count' }) countText!: HTMLSpanElement;
@onEvent({ ref: 'decrement', type: 'click' })
decrement() {
if (this.value > 0) {
this.value -= 1;
}
}
@onEvent({ ref: 'increment', type: 'click' })
increment() {
this.value += 1;
}
@onUpdated('value')
syncCount() {
this.countText.textContent = String(this.value);
}
}See Also
- See RadiantElement for the lower-level base class.
- See Slots for projected authored markup.
- See JSX SSR for SSR and hydration.
- See Radiant Todo App for a mixed architecture example.