Stars: 189
Forks: 3
Pull Requests: 0
Issues: 0
Watchers: 4
Last Updated: 2023-05-18 17:55:06
Swap.js is a "HTML-over-the-wire" AJAX-navigation micro-library
License: MIT License
Languages: JavaScript, HTML, PHP, Hack, CSS
Swap.js is a JavaScript micro-library which facilitates AJAX-style navigation in web pages, in less than ~ 100 lines of code. (See "Why?" paragraph below)
This is inspired by the recent libraries that make server-side-rendering and "HTML-over-the-wire" techniques popular again (HTMX, Unpoly, Hotwire...).
In short, portions of a web page can be replaced by new content sent directly from the server as HTML fragments, in a very simple way.
Demo here using this library: Demo
Features:
Important aspects:
<a href="..."
navigation still works if JavaScript is disabled in the browser (progressive enhancement)Key idea:
<a href="newpage.html" swap-target="#container" swap-history="true">Click me</a> <div id="container">Container</div>`
When you click on "Click me", the element
#container
is replaced bynewpage.html
's#container
. Simple isn't it?
See demo1/
folder.
index.html
<body>
<a href="index.html" swap-target="#container" swap-history="true">Home</a>
<a href="screen2.html" swap-target="#container" swap-history="true">Go to screen 2</a>
<div id="container">Container</div>
<script src="../swap.js"></script>
</body>
screen2.html
<body>
<a href="index.html" swap-target="#container" swap-history="true">Home</a>
<a href="screen2.html" swap-target="#container" swap-history="true">Go to screen 2</a>
<div id="container">You are on screen 2!</div>
<script src="../swap.js"></script>
</body>
Of course, in real life, you don't want to duplicate the same header and footer in multiple HTML files, and you will want to use server-side rendering: for a more complete example, see demo2/
folder with PHP code, multiple screens, multiple containers to be replaced, and also with some JS code that is run automatically when elements are inserted/destroyed in the DOM.
The folder demo3-email/
is another example of usage of the library. Nearly no JS is written, but mostly HTML attributes.
You can use these 3 features:
swap-target
(HTML attribute)
If present on a <a href="..."
link, then, when clicked, a HTTP request is done with fetch()
and the HTML fragment of the response matched by the CSS selector swap-target
will replace the part of the current page matched by this same selector.
This little detail is quite powerful because it allows you to continue to always render the full page server-side, no matter if only a HTML fragment will be used client-side (because AJAX navigation) or if the full page is required (for example, because the user did a refresh on the navigator). If you find in certain cases that it's a waste of bytes to send the full page in every case you can also render only a fragment server-side, based on the presence of HTTP request header swap-target
($_SERVER['HTTP_SWAP_TARGET']
in PHP), but this is purely optional.
swap-history
(HTML attribute)
If true
, a new browser history element will be pushed when the link is clicked.
When going back in history, an AJAX-call is made to update <body>
based on the history URL.
If you want to update something else than <body>
when going back in history, you can set the HTML attribute swap-history-restore
on the element which will be restored.
Loader/unloader JS functions when DOM elements are added/removed
Sometimes, you want to execute JS code when a new HTML fragment is inserted, or when it is removed. Here is how it works:
Swap.loaders['.screen2'] = () => {
console.log("An element with class screen2 has just been inserted in the DOM.")
var task = setInterval(() => { console.log("On repeat!"); }, 1000);
return () => { clearInterval(task); }; // in a loader function, you return an unloader function which will be executed when the element is removed from DOM
}
When you start a new web project and decide to use a rather new library xyz.js, you always take the risk that:
For this reason, this micro-library will always stay single-file and not have more than ~ 100 lines of code. No complex feature will be added, it will stay very basic. The benefit of all this is that you can read, understand, and improve the full code of the micro-library in less than 1 hour of your time.
This project's source code was initially much larger than its current state, with more complex mechanisms (for the same result), and I spent good time simplifying it and keep (what I find) the most elegant solution. It looks simple now, but it wasn't initially ;) (the use of MutationObserver API was helpful).
Issues, ideas, discussions are welcome - please open an issue before doing a pull request to be sure it is necessary.
Which simple feature would you want to to see included? After all the current code is < 50 lines of code, so there is plenty of room until reaching the 100 lines of code limit :)
Joseph Ernest
For R&D, Python, data science, automation consulting/freelancing requests, please contact me on https://afewthingz.com.
Sponsors are welcome to support the development of my open-source projects.
I am currently sponsored by CodeSigningStore.com. Thank you to them for providing a DigiCert Code Signing Certificate and supporting open source software.
MIT