What is Aegis?

Zero-build reactive UI engine. One ES module. No build step. No dependencies. Your server renders the HTML; Aegis wakes up the parts that need to be alive.

<!-- rendered by Django / Rails / Laravel / Go / PHP … -->
<div data-aegis="counter" data-start="5">
    <button>Clicked 5 times</button>
</div>

<script type="module">
import { island } from 'https://aegisjs.com/0.7.0/aegis.min.js';

island('counter', ({ props, signal, html }) => {
    const count = signal(props.start);
    return html`<button @click=${() => count.value++}>Clicked ${count} times</button>`;
}, { types: { start: Number } });
// no mount() call: every [data-aegis] on the page is hydrated after island()
</script>

That is the whole setup. The server HTML is visible before JavaScript runs and indexed by search engines; the island replaces it with a live template and keeps working after any server-driven swap.

  • Server HTML stays the source of truth. No Node SSR, no client tree that re-renders what the server already sent.
  • A form works without JavaScript. wireForm() only improves it: live validation, 422 errors on the right fields.
  • An island hydrates inside htmx, Turbo or jQuery pages. Markup inserted later wakes up too.
  • 30 KB gzip for islands + templates, zero dependencies, one file you can read. Pin a version, add a hash, ship.

Start here: Getting started (a base.html for Django, Laravel, Rails and Go) · from Alpine · with htmx · when not to use Aegis.

Mental model — 4 rules#

  1. ${x.value} is a snapshot, ${x} and ${() => …} are live. A signal or a function in a template re-renders on change; a plain value renders once (dev warns with E019).
  2. Everything lives in a scope. Effects, listeners, timers and resources created inside island() / mount() die with the component. Outside a scope you get E001.
  3. Use the ctx versions. on, effect, interval, observe from the setup context are bound to the component's scope; the imported ones are not.
  4. Data never goes through innerHTML. Data goes through ${} in html`` (text nodes, never parsed). Server HTML goes through swap() / adopt().

Edit this page on GitHub