Menu
Public repository / fee5b6c2cde89fa6bf8dc51068af7336b56a88b8
AkurAI-Framework / site/frontend/reactivity.html
Latest change 7003a93dcc0adf28fa6dc8af98472bbcf4f2091e - feat(frontend): signals + directives reactivity runtime by Ólafur Búi Ólafsson
{% include "header" %}
<main class="container">
<header class="page-head">
<span class="eyebrow">Live demo</span>
<h1>Reactivity</h1>
<p class="lede">Every widget below is wired by <code>signals.js</code> — a few-KB,
no-build, zero-dependency reactivity runtime that enhances this server-rendered
HTML in place. Signals track what they read; directives re-render when those
signals change. <a href="/docs/reactivity">Read how it works →</a></p>
</header>
<section class="split rt-grid">
<!-- Counter: data-text + data-on:click -->
<article class="card" data-scope data-state='{"count":0}'>
<header class="rt-head">
<h3>Counter</h3>
<span class="status ok">data-text · data-on</span>
</header>
<p class="muted small">A signal behind <code>count</code>. The buttons mutate it;
<code>data-text</code> re-renders the number reactively.</p>
<div class="rt-num" id="counter-value" data-text="count">0</div>
<div class="btn-row">
<button class="btn btn-secondary" id="counter-dec" data-on:click="count--">−1</button>
<button class="btn btn-primary" id="counter-inc" data-on:click="count++">+1</button>
<button class="btn btn-ghost" id="counter-reset" data-on:click="count = 0">Reset</button>
</div>
</article>
<!-- Two-way binding: data-model + data-text -->
<article class="card" data-scope data-state='{"name":"world"}'>
<header class="rt-head">
<h3>Two-way binding</h3>
<span class="status ok">data-model</span>
</header>
<p class="muted small">Type below. <code>data-model</code> binds the input to a
signal, and <code>data-text</code> echoes it live — no event wiring by hand.</p>
<form class="rt-form" autocomplete="off" data-on:submit="$event.preventDefault()">
<input id="echo-input" type="text" placeholder="Type a name…"
aria-label="Your name" data-model="name" />
</form>
<p class="rt-echo">Hello, <strong id="echo-output" data-text="name">world</strong>!</p>
</article>
</section>
<section class="split rt-grid">
<!-- Conditional: data-show -->
<article class="card" data-scope data-state='{"open":true}'>
<header class="rt-head">
<h3>Conditional</h3>
<span class="status ok">data-show</span>
</header>
<p class="muted small">The checkbox is a boolean signal; <code>data-show</code>
toggles the panel's visibility from it.</p>
<label class="switch">
<input type="checkbox" class="switch-input" role="switch"
id="toggle-input" data-model="open" checked />
<span class="switch-text">Reveal the panel</span>
</label>
<div class="alert alert-info" id="secret-panel" data-show="open" style="margin-top:1rem">
<strong>Visible.</strong> <span>This panel is shown only while the signal is true.</span>
</div>
</article>
<!-- List: data-for -->
<article class="card" data-scope data-state='{"items":["Signals","Effects","Directives"],"draft":""}'>
<header class="rt-head">
<h3>List rendering</h3>
<span class="status ok">data-for</span>
</header>
<p class="muted small">A <code><template data-for></code> renders one row per
array item. Adding an item replaces the array, and the list re-renders.</p>
<form class="rt-form" autocomplete="off"
data-on:submit="$event.preventDefault(); if (draft.trim()) { items = items.concat(draft.trim()); draft = '' }">
<input id="list-input" type="text" placeholder="Add an item…"
aria-label="New item" data-model="draft" />
<button class="btn btn-primary" type="submit" id="list-add">Add</button>
</form>
<ul class="rt-log" id="list-output" aria-live="polite">
<template data-for="(item, index) in items">
<li><span data-text="index + 1"></span>. <span data-text="item"></span></li>
</template>
</ul>
</article>
</section>
<section class="container cta">
<h2>Reactive UI, with zero runtime dependencies.</h2>
<div class="btn-row center">
<a class="btn btn-secondary" href="/docs/reactivity">Reactivity docs</a>
<a class="btn btn-secondary" href="https://github.com/olibuijr/AkurAI-Framework">Source on GitHub</a>
</div>
</section>
</main>
<script type="module" src="/signals.js"></script>
{% include "footer" %}