The Fixi Project is a collection of five small web libraries based on other libraries we work on.
Each library in The Fixi Project is constrained to have an unminified, uncompressed source size smaller than the excellent Preact library's min.gz'd size (~ 4.7kb).
The five libraries each provide independent bits of functionality, but are designed to compose well. You can mix and match them as you see fit.
fixi.js is the original and main library in this collection. It is based on htmx and, like htmx,
makes it possible to issue HTTP requests from elements in response to events.
Here is a fixi-powered button:
<button fx-action="/like" fx-method="post">
Like
</button>This button will issue an HTTP POSt to /like when it is clicked and will replace itself with whatever HTML content the
server responds with. This simple concept is a surprisingly powerful way to build web applications.
You can read more about how fixi works on its homepage.
moxi.js adds inline scripting and DOM-based reactivity. It is based on hyperscript and lets
you put behavior directly on elements via on-* attributes, plus a live attribute that re-runs whenever the page
changes.
Here is a moxi-powered button:
<button on-click="this.disabled = true; this.innerText = 'thanks!'">
Click me
</button>This button disables itself and updates its text when clicked, without a separate <script> block. Each on-* handler
is compiled into an async function with access to helpers like q() (a proxy over a set of matched elements), trigger(),
wait(), and debounce().
You can read more about how moxi works on its homepage.
ssexi.js is a companion library for fixi that
adds Server-Sent Events support. It is inspired
by htmx's SSE extension: whenever a fixi
response comes back with Content-Type: text/event-stream, ssexi takes over the swap loop and streams each message into
the target as it arrives.
Here is an ssexi-powered log:
<button fx-action="/events" fx-swap="beforeend" fx-target="#log">
Start
</button>
<div id="log"></div>When /events responds with an SSE stream, each data: line is appended to #log. Messages with a named event:
field fire DOM events (fx:sse:<name>) instead of swapping, which gives you a clean seam for JavaScript hooks like
progress or "done" signals.
You can read more about how ssexi works on its homepage.
paxi.js adds a morph swap strategy to fixi. It is based on idiomorph
and patches an existing subtree into the shape of a new one in place, matching elements by id rather than replacing them
wholesale.
Here is a paxi-powered swap:
<button fx-action="/counter" fx-swap="morph" fx-target="#count">
Increment
</button>
<span id="count">0</span>When the server responds with an updated <span id="count">1</span>, paxi morphs the existing span instead of replacing
the node. The practical upshot is that focus, selection, input state, and event listeners survive a swap. It also allows
you to use CSS transitions.
You can read more about how paxi works on its homepage.
rexi.js is a small fluent wrapper around fetch(), inspired by hyperscript's
fetch command. It handles the usual boring parts of calling an HTTP endpoint
from JavaScript: serializing a form or a plain object as a body, throwing on non-2xx responses, decoding the result, and
aborting on demand.
Here is a rexi-powered POST:
let user = await post('/users', {name: 'carson'}).json()rexi serializes the object as a JSON body, throws if the server returns an error status, and decodes the JSON response
for you. It also accepts FormData, URLSearchParams, or a form Element directly as the body, so it slots neatly
into moxi handlers and fixi-driven pages.
You can read more about how rexi works on its homepage.
All five libraries are also published as a single pre-concatenated, minified, and brotli-compressed bundle under the
the-fixi-project npm package:
<script src="https://cdn.jsdelivr.net/npm/the-fixi-project/dist/the-fixi-project.min.js"></script>The entire fixi project comes in at ~4.4kb when brotli-compressed.
From a fresh checkout of this repo:
npm install # installs playwright + terser (dev-only)
npm run clone # clones each sub-project repo into its directory
npm test # runs the full test suite across all libraries (headless)
npm run build # builds the all-in-one bundle into dist/
npm run serve # serves the project over http://localhost:8000npm test accepts a subset of project names, so npm test rexi paxi runs only those two.
BSD-0 (Zero-Clause BSD) across all libraries.