lightview
Version:
A reactive UI library with features of Bau, Juris, and HTMX plus safe LLM UI generation
131 lines (103 loc) • 4.8 kB
HTML
<!-- SEO-friendly SPA Shim -->
<script src="/lightview-router.js?base=/index.html"></script>
<div class="docs-layout">
<aside class="docs-sidebar" src="./nav.html" data-preserve-scroll="docs-nav"></aside>
<main class="docs-content">
<h1>Signals</h1>
<p>
Signals are the heart of Lightview's reactivity. They hold values that can change over time,
and automatically notify anything that depends on them.
</p>
<h2>Creating Signals</h2>
<pre><code>const { signal } = Lightview;
// Create a signal with an initial value
const count = signal(0);
const name = signal('World');
const items = signal([]);
const user = signal({ name: 'Alice', age: 25 });</code></pre>
<h2>Reading Values</h2>
<pre><code>// Two ways to read
console.log(count.value); // Property access: 0
console.log(count()); // Function call: 0
// Both work identically - pick your style</code></pre>
<h2>Writing Values</h2>
<pre><code>// Two ways to write
count.value = 5; // Property assignment
count(10); // Function call with argument
// Both trigger reactive updates</code></pre>
<h2>Reactive UI</h2>
<p>
The magic happens when you use signals in your UI. Wrap expressions in functions to make them reactive:
</p>
<pre><code>const { signal, tags } = Lightview;
const { div, p, button } = tags;
const count = signal(0);
// Static - won't update
p(`Count: ${count.value}`) // ❌ "Count: 0" forever
// Reactive - updates automatically
p(() => `Count: ${count.value}`) // ✅ Updates when count changes!</code></pre>
<div class="code-example">
<div class="code-example-preview" id="signal-demo"></div>
<div class="code-example-code">
<pre><code>const count = signal(0);
div(
p(() => `Count: ${count.value}`),
button({ onclick: () => count.value++ }, '+1')
)</code></pre>
</div>
</div>
<h2>Named Signals</h2>
<p>
You can give signals a name for easy access across your application:
</p>
<pre><code>// Create a named signal and keep it in sessionStorage
const count = signal(0, 'count');
// Retrieve it elsewhere (even in another file)
const sameCount = signal.get('count');
// Get or create with default value
// If ' ' exists, returns it. If not, creates it with 100.
const score = signal.get('count', 0);</code></pre>
<h2>Stored Signals</h2>
<p>
You can store named signals in Storage objects (e.g. sessionStorage or localStorage) for persistence. It
will be saved any time there is a change.
</p>
<pre><code>const count = signal(0, {name:'count', storage:sessionStorage});
// Retrieve it elsewhere (even in another file)
const sameCount = signal.get('count');
// Get or create with default value
// If ' ' exists, returns it. If not, creates it with 100.
const score = signal.get('count', {storage:sessionStorage, defaultValue:0});</code></pre>
<p>Note: Manually updating the value in storage will not trigger updates.</p>
<h2>Tips & Patterns</h2>
<h3>Derived State</h3>
<p>For values computed from signals, use <a href="./computed">computed()</a> instead:</p>
<pre><code>const count = signal(0);
const doubled = computed(() => count.value * 2); // Auto-updates</code></pre>
<h3>Objects & Arrays</h3>
<p>For deep reactivity on objects/arrays, consider <a href="./state">state()</a>:</p>
<pre><code>// Signal: only triggers on reassignment
const items = signal([1, 2, 3]);
items.value.push(4); // ❌ Won't trigger update
items.value = [...items.value, 4]; // ✅ Triggers update
// State: deep reactivity
const items = state([1, 2, 3]);
items.push(4); // ✅ Triggers update automatically</code></pre>
</main>
</div>
<script>
(function () {
const { signal, tags } = Lightview;
const { div, p, button } = tags;
const count = signal(0);
const demo = div({ style: 'display: flex; align-items: center; gap: 1rem;' },
p({ style: 'margin: 0; font-size: 1.25rem;' }, () => `Count: ${count.value}`),
button({
onclick: () => count.value++,
style: 'padding: 0.5rem 1rem; cursor: pointer; background: var(--site-primary); color: white; border: none; border-radius: 6px;'
}, '+1')
);
const container = document.getElementById('signal-demo');
if (container) container.appendChild(demo.domEl);
})();
</script>