Radiant0.3.0-rc.5

Radiant Counter

The smallest example comparing the two main RadiantElement host modes.

Live Comparison

JSX-Owned Host

5

RadiantElement Host

5

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