Elements
Lightview is uniquely flexible. It doesn't force you into a single way of describing your DOM. Whether you prefer concise JavaScript functions, structured JSON, or standard HTML, the same signal-based reactivity powers it all.
Comparison
| Syntax | Style | Best For | Requirement |
|---|---|---|---|
| Tagged API | div(h1('Title')) |
Application logic, dynamic UIs | Core |
| vDOM | { tag: 'div', ... } |
Serialization, data-driven UI | Core |
| Object DOM (oDOM) | { div: { ... } } |
Concise templates, config files | Lightview X |
| Custom Elements | <lv-button> |
Progressive enhancement, CMS | Lightview X |
| cDOM (Experimental) | 'sum($/cart/items...price)' |
Declarative logic, LLM generation | lightview-cdom.js |
Note: An exciting 5th option is coming, the Computational DOM, a.k.a. cDOM.
Tagged API
Inspired by Bau.js, this is the most concise way to build UIs in JavaScript. Every HTML tag is available as a function.
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')
);
$('#example').content(app);
Pros: Extremely readable, feels like "HTML in JS" without a compiler, full IDE autocomplete.
vDOM Syntax
Represent your UI as plain JavaScript objects. This is the underlying format for all non-string elements in Lightview.
const { signal, element, $, tags } = Lightview;
const { div } = tags;
const count = signal(0);
// will accept either a function or string as tag, function avoids typos better
const app = { tag:div, attributes: { class: 'container' }, children: [
{ tag: 'h1', attributes: {}, children: ['Hello Lightview'] },
{ tag: 'p', attributes: {}, children: [() => `Count: ${count.value}`] },
{ tag: 'button', attributes: { onclick: () => count.value++ }, children: ['Click me'] }
]};
$('#example').content(app);
Pros: Unambiguous, easy to serialize/deserialize as JSON, perfect for programmatic generation.
Object DOM (oDOM)
A more compact JSON representation provided by Lightview X. It uses the tag name as a key to reduce verbosity.
const { signal, tags, $ } = Lightview;
const count = signal(0);
const app = { div: { class: 'container', children: [
{ h1: { children: ['Hello Lightview'] } },
{ p: { children: [() => `Count: ${count.value}`] } },
{ button: { onclick: () => count.value++, children: ['Click me'] } }
]}};
$('#example').content(app);
Pros: Highly readable for templates stored in JSON, significantly less boilerplate than standard vDOM.
HTML Custom Elements
Use standard HTML tags to instantiate Lightview components. Ideal for multi-page apps or content managed by a CMS.
<!-- Requires registered components & Lightview X -->
<lv-card>
<h3 slot="title">User Profile</h3>
<lv-badge color="primary">Admin</lv-badge>
<p>Active since 2024</p>
<lv-button onclick="alert('Clicked!')">Settings</lv-button>
</lv-card>
Pros: Familiar HTML syntax, framework-agnostic, excellent for progressive enhancement of server-rendered pages.
Pseudo-elements
Lightview supports special "pseudo-elements" that perform specific tasks rather than creating a standard HTML element.
shadowDOM
The shadowDOM tag allows you to attach a Shadow Root to the parent element and render children
inside it. This is useful for building encapsulated components without manual attachShadow
calls.
const { tags } = Lightview;
const { div, shadowDOM, h2, p } = tags;
const MyComponent = () => div(
shadowDOM({ mode: 'open', styles: ['/my-styles.css'] },
h2('Encapsulated Title'),
p('This content is inside the shadow root.')
)
);
text
The text tag creates a single Text node containing the concatenated content of all
its children, separated by spaces. It supports reactivity, meaning if any child is a function, the text node
will update automatically.
const { tags, signal } = Lightview;
const { div, text } = tags;
const firstName = signal('John');
const lastName = signal('Doe');
const greeting = div(
text('Hello,', () => firstName.value, () => lastName.value, '!')
);
// Initial result: Hello, John Doe !
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');