Markdown Files
name: fixi description: | fixi.js (3.4kb raw / 1.2kb brotli) is a miniature version of htmx offering simplified AJAX/HTML swap functionality. It enables any element to issue HTTP requests in response to events and place response HTML anywhere in the document using declarative attributes.
when_to_load: | LOAD when the user:
- Works with fixi.js attributes (fx-action, fx-target, fx-swap, etc.)
- Implements AJAX-driven HTML swaps in vanilla JS projects
- Needs lightweight htmx-like functionality without the full library
- Configures request handling with fixi events (fx:config, fx:swapped, etc.)
- Implements patterns like inline editing, lazy loading, load more, form submission
scope: | The fixi skill covers:
- All fixi.js core attributes and their usage
- fixi event lifecycle and customization
- Request configuration (headers, body, method, etc.)
- Swap modes (outerHTML, innerHTML, morph, beforeend, etc.)
- Per-element and global configuration patterns
- Common use cases and examples
- Integration with moxi for event handling
- View Transitions API integration
fixi.js Skill Reference
Overview
fixi.js (3.4kb raw / 1.2kb brotli) is a miniature version of htmx and offers similar, simplified functionality. It makes it possible for any element to issue HTTP requests in response to any event, and place the response HTML anywhere in the document.
Like htmx, fixi uses attributes to add behaviors to HTML elements.
A Simple Demo
Here is a fixi-powered button that loads a fragment into a panel:
<button fx-action="/profile"
fx-target="#panel"
fx-swap="innerHTML">
Load profile
</button>
<output id="panel"></output>
Clicking this button issues a GET /profile request & whatever HTML comes back is placed inside #panel.
This demonstrates the core idea of fixi: an element issues a request, gets some HTML back & places it somewhere in the DOM.
Attributes
The five core fixi attributes are:
| attribute | description | default |
|---|---|---|
fx-action | the URL to issue a request to | required |
fx-method | the HTTP verb to use | GET |
fx-trigger | the DOM event that fires the request | a sensible value based on element type |
fx-target | a CSS selector for the element to swap into | the element itself |
fx-swap | how to insert the response (outerHTML, innerHTML, beforeend, etc.) | outerHTML |
Events
fixi dispatches a set of events during its lifecycle:
| event | when |
|---|---|
fx:init | just before fixi wires up an element. Cancelable: preventDefault() skips this element. |
fx:inited | after the element is fully wired up. Does not bubble. |
fx:process | listened for on document; processes evt.target and its descendants. Dispatch this after manual DOM changes to pick up new fixi-powered nodes. |
fx:config | the request has been triggered but not yet sent. Mutate evt.detail.cfg to inject headers, set a confirm callback, rewrite the URL, etc. |
fx:before | immediately before fetch() is called. |
fx:after | the response has arrived, but before the swap. |
fx:swapped | the response has been swapped in (and any View Transition has finished). |
fx:error | the fetch() threw an exception |
fx:finally | after every request, success or failure. |
The most commonly used events are fx:config, to customize the request before it goes out, and fx:swapped, to react to freshly inserted content.
Modifying The Request Config
Each fixi request is configured through an object exposed on the fx:config event's evt.detail.cfg.
Listening for that event and mutating cfg is how you customize a request before it is sent.
| field | controls |
|---|---|
cfg.action | the URL fixi will fetch |
cfg.method | the HTTP verb |
cfg.headers | a plain object of headers to send |
cfg.body | the request body (FormData, string, etc.) |
cfg.target | the element the response will be swapped into |
cfg.swap | the swap mode (outerHTML, innerHTML, morph, etc.) |
cfg.confirm | an optional () => boolean callback fixi awaits before sending |
cfg.transition | the View Transition function, or false to disable |
cfg.fetch | the fetch implementation (replace for mocking) |
Per-Element Configuration
Attach an on-fx:config handler with moxi (or a plain addEventListener) to customize a single element's requests.
moxi exposes every key on event.detail as a bare name, so cfg resolves directly:
<button fx-action="/things/42" fx-method="DELETE"
on-fx:config="cfg.confirm = () => confirm('Delete this thing?')">
delete
</button>
Global Configuration
Listen on document to apply the same modification to every fixi request. This is the right place for auth headers, request-ID injection, or a uniform URL prefix:
document.addEventListener('fx:config', (e) => {
e.detail.cfg.headers.Authorization = `Bearer ${getToken()}`
})
Default Configuration via window.fixiCfg
For values you want to set once at page load, fixi reads window.fixiCfg for default swap, transition, and headers:
<script>
window.fixiCfg = {
swap: "morph",
headers: { "X-CSRF-Token": "abc123" },
}
</script>
<script src="fixi.js"></script>
Per-element listeners always win over these defaults.
Examples
Inline Editing
A common fixi pattern is to click a row (or div) and to swap in an edit form, then submit to swap back to a display row.
Both of these are plain fixi swaps:
<tr id="row-42">
<td>Ada</td>
<td>
<button fx-action="/contacts/42/edit"
fx-target="#row-42"
fx-swap="outerHTML">edit</button>
</td>
</tr>
The server returns either the display row or the edit form depending on the URL. The edit form posts back to the same row id; the response replaces it with a fresh display row.
Form Submission
When the fixi-powered element is a <form>, the submit event triggers the request & fixi includes the form's inputs in the request body (or URL):
<form fx-action="/signup" fx-method="POST"
fx-target="#status" fx-swap="innerHTML">
<input name="email" type="email" required placeholder="email">
<input name="password" type="password" required minlength="8" placeholder="password">
<button type="submit">Sign up</button>
</form>
<output id="status"></output>
On submit, fixi POSTs the email and password as form data and swaps whatever HTML comes back into #status.
Click to Delete
fx-method="DELETE" issues a DELETE request: if the server responds with an empty body, the default outerHTML swap removes the targeted element from the DOM.
<li id="todo-42">
Buy milk
<button fx-action="/todos/42" fx-method="DELETE"
fx-target="#todo-42" fx-swap="outerHTML">x</button>
</li>
The button targets its containing <li> so the whole row vanishes when the server responds.
Load More
The Load More button sits in the last row of a table, spanning all columns. By targeting that row and relying on the default outerHTML swap, clicking the button replaces the whole row with more data rows plus a fresh "Load more" row:
<table>
<tbody>
<tr><td>Ada</td><td>ada@example.com</td></tr>
<tr><td>Grace</td><td>grace@example.com</td></tr>
<tr id="more">
<td colspan="2">
<button fx-action="/people?page=2" fx-target="#more">Load more</button>
</td>
</tr>
</tbody>
</table>
The server responds with the next page of <tr> rows followed by a fresh <tr id="more"> row pointing at ?page=3. When the pages run out, the server omits the placeholder row and the pagination ends naturally.
Lazy Loading
Any fixi event can be used as an fx-trigger, including the fx:init event that fires when fixi wires an element up.
That makes a "load this content asynchronously" simple to implement:
<div fx-action="/expensive-data"
fx-trigger="fx:init">
loading...
</div>
When fixi initializes the div it dispatches fx:init the element issues GET /expensive-data, and the response replaces the element.
Workflows
Setting Up fixi
- Install the library: Download
fixi.jsand include it in your project - Add to HTML: Include the script tag, optionally with
window.fixiCfgfor defaults - Mark up elements: Add
fx-actionand other attributes to interactive elements - Server-side: Ensure your server returns HTML fragments matching the target selectors
Debugging fixi
- Check browser console for errors during initialization or request processing
- Listen to events: Add
document.addEventListener('fx:error', e => console.log(e)) - Inspect network requests to verify URLs, methods, and headers
- Check target selectors exist in the DOM when response arrives
Common Patterns
- Progressive Enhancement: Use fixi alongside traditional form submissions
- Error Handling: Use
fx:errorto show user-friendly error messages - Loading States: Combine
fx:beforeandfx:afterto show/hide spinners - Confirmation: Use
cfg.confirmfor destructive actions - CSRF Protection: Add CSRF tokens via
window.fixiCfg.headersorfx:config
Best Practices
- Use semantic swap modes:
outerHTMLfor element replacement,innerHTMLfor content updates,beforeendfor appending - Keep server responses minimal: Return only the HTML fragment needed, not full page
- Use
morphswap for smooth DOM updates without layout shifts - Centralize auth via
fx:configon document to avoid repetition - Handle errors gracefully: Always provide user feedback for failed requests
- Use View Transitions for smooth page updates (set
cfg.transition) - Test without JavaScript: Ensure basic functionality works without fixi as fallback
Quick Reference Card
┌─────────────────────────────────────────────────────────────┐
│ FIXI.JS QUICK REFERENCE │
├─────────────────────────────────────────────────────────────┤
│ ATTRIBUTES │
│ fx-action - URL (required) │
│ fx-method - HTTP verb (default: GET) │
│ fx-trigger - Event trigger (default: element-specific) │
│ fx-target - CSS selector for swap target │
│ fx-swap - Swap mode (default: outerHTML) │
├─────────────────────────────────────────────────────────────┤
│ SWAP MODES │
│ outerHTML, innerHTML, beforeend, afterend, beforebegin, │
│ afterbegin, morph, text, none │
├─────────────────────────────────────────────────────────────┤
│ KEY EVENTS │
│ fx:config - Modify request before send │
│ fx:before - Just before fetch() │
│ fx:after - Response arrived, before swap │
│ fx:swapped - After swap completed │
│ fx:error - Request failed │
│ fx:finally - Always runs (success or failure) │
├─────────────────────────────────────────────────────────────┤
│ CONFIG FIELDS (evt.detail.cfg) │
│ action, method, headers, body, target, swap, confirm, │
│ transition, fetch │
└─────────────────────────────────────────────────────────────┘