---
title: "Counter"
description: "A small counter used to compare JSX-owned and authored-light-DOM RadiantElement host patterns."
group: Examples
order: 1
---
import { RadiantJsxCounter, RadiantElementCounter } from '@/components/radiant-counter';
export const config = {
dependencies: {
components: [RadiantJsxCounter, RadiantElementCounter],
},
};
# 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
```tsx
import { RadiantElement, customElement, prop } from '@ecopages/radiant';
export type RadiantCounterProps = {
value?: number;
};
@customElement('radiant-counter')
export class RadiantCounter extends RadiantElement {
@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 (
<>
{this.$.value}
>
);
}
}
```
## 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.
```html
5
```
The script attaches to existing markup. `@onEvent` handles clicks. `@bindTo` copies `value` onto the authored count node.
```ts
import { RadiantElement, bindTo, customElement, onEvent, prop } from '@ecopages/radiant';
@customElement('counter-element')
export class CounterElement extends RadiantElement {
@prop({ type: Number, reflect: true, defaultValue: 0 })
@bindTo({ ref: 'count', text: true })
declare value: number;
@onEvent({ ref: 'decrement', type: 'click' })
decrement() {
if (this.value > 0) {
this.value -= 1;
}
}
@onEvent({ ref: 'increment', type: 'click' })
increment() {
this.value += 1;
}
}
```
## See Also
- See [RadiantElement](/docs/components/radiant-element) for the lower-level base class.
- See [Slots](/docs/components/slots) for projected authored markup.
- See [JSX SSR](/docs/ssr/jsx-ssr) for SSR and hydration.
- See [Radiant Todo App](/docs/examples/todo-app) for a mixed architecture example.