2 · Computed totals
computed() derives a value from other signals. It’s lazy and memoised — recomputes only when its dependencies change, and only when a consumer reads it.
What to look at: three inputs (bill, tip %, party size), three derived values (tip, total, per-person). The total computed depends on the tip computed, which depends on bill and tipPct — that chain re-derives only what changed. Edit the bill: tip, total, and perPerson all update; edit just party size and tip is not recomputed.
import { signal, computed, mount, delegate } from 'kerfjs';
const bill = signal(48);const tipPct = signal(18);const partySize = signal(3);
const tip = computed(() => bill.value * tipPct.value / 100);const total = computed(() => bill.value + tip.value);const perPerson = computed(() => total.value / Math.max(1, partySize.value));
const fmt = (n: number) => `$${n.toFixed(2)}`;
const inputs = { bill, tipPct, partySize } as const;
const root = document.getElementById('app')!;
mount(root, () => ( <div class="kerf-stack" style="max-width: 24rem;"> <div style="display: grid; grid-template-columns: 8rem 1fr; gap: 0.5rem 1rem; align-items: center;"> <label for="kerf-bill">Bill</label> <input id="kerf-bill" type="number" data-input="bill" value={String(bill.value)} step="0.01" /> <label for="kerf-tip">Tip %</label> <input id="kerf-tip" type="number" data-input="tipPct" value={String(tipPct.value)} step="1" /> <label for="kerf-party">Party size</label> <input id="kerf-party" type="number" data-input="partySize" value={String(partySize.value)} step="1" min="1" /> </div> <div class="kerf-output"> <div style="display: grid; grid-template-columns: 1fr auto; row-gap: 0.25rem; column-gap: 1.5rem;"> <span>Tip</span> <strong class="kerf-mono">{fmt(tip.value)}</strong> <span>Total</span> <strong class="kerf-mono">{fmt(total.value)}</strong> <span>Per person</span> <strong class="kerf-mono">{fmt(perPerson.value)}</strong> </div> </div> </div>));
delegate(root, 'input', 'input[data-input]', (_, el) => { const key = (el as HTMLElement).dataset.input as keyof typeof inputs; const v = Number((el as HTMLInputElement).value); if (Number.isFinite(v)) inputs[key].value = v;});