Creating Elements
Lightview gives you four ways to build UI. Pick your favorite—or mix and match. They all use the same reactive system under the hood.
Style 1: Tagged API
The most concise way. Destructure tag functions and compose naturally:
const { signal, tags } = Lightview;
const { div, h1, p, button } = tags;
const count = signal(0);
const app = div({ class: 'container' },
h1('Hello Lightview'),
p(() => `Count: ${count.value}`),
button({ onclick: () => count.value++ }, 'Click me')
);
document.body.appendChild(app.domEl);
Style 2: Element Function
More explicit. Good when you need dynamic tag names:
const { signal, element } = Lightview;
const count = signal(0);
const app = element('div', { class: 'container' }, [
element('h1', {}, ['Hello Lightview']),
element('p', {}, [() => `Count: ${count.value}`]),
element('button', { onclick: () => count.value++ }, ['Click me'])
]);
document.body.appendChild(app.domEl);
Style 3: vDOM Syntax
Plain JSON objects. Great for storing in databases or generating programmatically:
const { signal, element } = Lightview;
const count = signal(0);
const app = element('div', { class: 'container' }, [
{ tag: 'h1', attributes: {}, children: ['Hello Lightview'] },
{ tag: 'p', attributes: {}, children: [() => `Count: ${count.value}`] },
{ tag: 'button', attributes: { onclick: () => count.value++ }, children: ['Click me'] }
]);
document.body.appendChild(app.domEl);
Style 4: Object DOM (lightview-x)
Compact JSON format. Requires the hypermedia extension:
// Enable Object DOM first
LightviewX.useObjectDOMSyntax();
const { signal, tags } = Lightview;
const { div } = tags;
const count = signal(0);
const app = div({ class: 'container' },
{ h1: { children: ['Hello Lightview'] } },
{ p: { children: [() => `Count: ${count.value}`] } },
{ button: { onclick: () => count.value++, children: ['Click me'] } }
);
document.body.appendChild(app.domEl);
Comparison
| Style | Pros | Cons |
|---|---|---|
| Tagged API | Most concise, natural to write | Requires destructuring |
| Element Function | Explicit, dynamic tag names | More verbose |
| vDOM | JSON serializable, easy to validate | Most verbose |
| Object DOM | Compact JSON, clean templates | Requires lightview-x |
Attributes & Events
Pass attributes as the first argument (Tagged API) or in the attributes object (others):
// Standard attributes
div({
id: 'my-div',
class: 'container active',
style: 'color: red;',
'data-value': '42'
})
// Reactive attributes - use functions!
div({
class: () => isActive.value ? 'active' : 'inactive',
style: () => `opacity: ${visible.value ? 1 : 0}`,
disabled: () => isLoading.value
})
// Event handlers - use "on" prefix
button({
onclick: (e) => handleClick(e),
onmouseenter: () => setHovered(true),
onmouseleave: () => setHovered(false)
})
Children
Children can be strings, numbers, elements, arrays, or functions:
div(
'Static text', // String
42, // Number (converted to string)
span('Nested element'), // Element
() => `Dynamic: ${value.value}`, // Reactive function
() => items.value.map(i => li(i.name)), // Reactive list
condition && span('Conditional') // Conditional (falsy = not rendered)
)
The domEl Property
Every Lightview element has a domEl property - the actual DOM node:
const myDiv = div({ class: 'box' }, 'Hello');
// Access the real DOM element
document.body.appendChild(myDiv.domEl);
// You can also manipulate it directly
myDiv.domEl.classList.add('another-class');
const { signal, tags } = Lightview;
const { div, input, p } = tags;
const name = signal('World');
const app = div(
input({
type: 'text',
value: name.value,
oninput: (e) => name.value = e.target.value
}),
p(() => `Hello, ${name.value}!`)
);