Radiant
@ecopages/radiant is an ultra-minimalist library for building reactive Web Components. It is designed to play perfectly with Ecopages' dependency management and SSR capabilities.
Introduction
Radiant uses standard CUSTOM Elements with a thin layer of decorators to handle reactivity and DOM queries. Use it when you need interactivity without the overhead of a full framework.
Component Example
import { customElement, reactiveProp, onEvent, query } from '@ecopages/radiant';
@customElement('radiant-counter')
export class RadiantCounter extends HTMLElement {
@reactiveProp()
value = 0;
@query('span')
display!: HTMLSpanElement;
@onEvent('click', 'button.increment')
inc() {
this.value++;
}
render() {
this.display.textContent = this.value.toString();
}
}Decorators
@customElement(tag: string)
Registers the class as a custom element with the given tag name.
@reactiveProp()
Marks a property as reactive. When the property changes, it automatically triggers a re-render or a specific update logic.
@onEvent(type: string, selector?: string)
Declaratively attaches an event listener. If a selector is provided, it uses event delegation.
@query(selector: string)
A shorthand for this.querySelector(selector). Returns the element every time it is accessed.
Using with Ecopages
Radiant hosts in JSX apps use Ecopages JSX (ecopagesJsxPlugin() enables Radiant SSR by default). See Creating Components for the full eco.component() pattern.
- Put element registration in a
*.script.tsfile (callcustomElements.defineor use@customElement). - Wrap the host in
eco.component()and declare the script withssr: trueso Ecopages evaluates it on the server before SSR. Useimport typefrom the script module when you only need props—no separate value import in the wrapper file. - Import the wrapper from pages; Ecopages discovers local
eco.component()imports automatically.
counter.script.ts:
export type CounterProps = { count?: number };
export class CounterElement extends HTMLElement {
static observedAttributes = ['count'];
connectedCallback() {
this.textContent = String(this.getAttribute('count') ?? 0);
}
attributeChangedCallback() {
this.textContent = String(this.getAttribute('count') ?? 0);
}
}
if (!customElements.get('radiant-counter')) {
customElements.define('radiant-counter', CounterElement);
}counter.tsx:
import { eco } from '@ecopages/core';
import type { JsxRenderable } from '@ecopages/jsx';
import type { CounterProps } from './counter.script';
export const Counter = eco.component<CounterProps, JsxRenderable>({
dependencies: {
scripts: [{ src: './counter.script.ts', ssr: true }],
},
render: ({ count = 0 }) => <radiant-counter count={count} />,
});Add lazy on the script entry when browser delivery should wait for idle, interaction, or visibility. lazy does not skip server registration when ssr: true is set.