@state
@state is the preferred name for internal reactive state in Radiant.
Use it for values that should trigger updates but are not part of the custom element's public attribute API.
Example
import { RadiantElement, customElement, onEvent, state } from '@ecopages/radiant';
@customElement('counter-display')
export class CounterDisplay extends RadiantElement {
@state count = 0;
@onEvent({ selector: 'button', type: 'click' })
increment() {
this.count += 1;
}
override render() {
return (
<div>
<p>Count: {this.$.count}</p>
<button type="button">Increment</button>
</div>
);
}
}How It Works Behind The Scenes
@state registers host-managed internal mutable state.
Under the hood it sets up a tracked state member on the host. Writes update that member state, which notifies @onUpdated listeners and keeps JSX bindings in sync. Render invalidation happens through the reactive render path when render() reads reactive members — no @onUpdated decorator is required for that.
The difference is naming and intent:
@prop(...)describes public external input.@statedescribes internal mutable state.
That split matters in docs, code review, and JSX typing because it keeps the public element contract separate from implementation-only state.
Unlike @signal, the field stays a plain host property. You read and write it with normal property syntax such as this.count += 1.
JSX Binding Defaults
Just like @prop(...), @state exposes companion bindings by default when bind is omitted.
So @state count = 0 gives you this.$.count automatically on RadiantElement hosts.
override render() {
return <p>Count: {this.$.count}</p>;
}When To Use It
- Use
@statefor local UI state. - Use
@prop(...)for public element API. - Use
@signalwhen the field itself should be a writable signal instance.
See @prop and RadiantElement.