npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

htswap

v0.21.3

Published

**Minimal, lightweight script for seamless AJAX-style UI content swapping.** By using `htswap`, your anchors and forms become enhanced and fast, not broken or replaced.

Downloads

85

Readme

🔄 htswap

Minimal, lightweight script for seamless AJAX-style UI content swapping. By using htswap, your anchors and forms become enhanced and fast, not broken or replaced.

The aim of htswap is to be a small, simple solution for removing reloads and implementing seamless content swapping, while allowing no-js users of your site to still have a good experience.

Inspired by a number of other libraries, see why it exists.

NPM Version jsDelivr hits (npm) NPM Downloads npm package minimized gzipped size

✴️️ Features

  • Dynamic Content: Content on the page is swapped dynamically, without reloading
  • Progressive Enhancement: Anchors, forms or whole sections can be opted in or out by a single attribute
  • Graceful Degradation: If JS is turned off, your anchors and forms still work
  • Smart Defaults: Built-in handling for browser shortcuts (Ctrl+Click), duplicate submission prevention, selector with server headers, request timeouts

Core:

  • Preserved Inlines: Inline scripts and styles are preserved and work as expected
  • Working Head: Swapped head tags work as expected, including styles and scripts
  • History Support: Browser back/forward buttons work seamlessly
  • Normal Fragments: Anchor links (#) work within swapped content, in-page and across pages
  • Maintained Scroll: Scroll position between swap history is maintained
  • Redirects Handled: Redirects are followed, including PRG pattern

Extra:

  • Loading States: Loading state can be styled (through aria-busy="true")
  • Multiple Targets: Swap multiple elements at once
  • History Modes: Swap without URL changes or replace the URL rather than pushing to it
  • Head Modes: Can append head elements rather than replace, or re-eval existing scripts
  • Auto Targeting: Automatically match server response elements by ID to client elements
  • Target Aliases: Map server selectors to different client selectors
  • Swap Modes: Control how content is inserted (innerHTML, outerHTML, beforeend, etc.)

📦 Installation

There are several build/distribution variants:

  • dist: modern and default (es2020)
  • dist-compat: compatible with older browsers (es2015)
  • dist-legacy: legacy support (es5)
  • dist-min: same as dist but minified
  • dist-min-compat: same as dist-compat but minified
  • dist-min-legacy: same as dist-legacy but minified

Any of the variants can be installed through the following methods:

  • Import from a CDN, changing the dist part to any of the variants:
<script type="module" src="https://cdn.jsdelivr.net/npm/htswap@latest/dist/htswap.js"></script>
  • Download a copy of the script file into your codebase from any of the dist directories here.

  • Install with a package manager and import any of the variants on the client side: pnpm i htswap

🛠️ Usage

After making sure htswap is imported, the data-htswap attribute can be on any element to let its children work with htswap automatically.

The attribute can be added on the body element to enable htswap on all the links and anchors in the site, without manually adding it to each element, if desired.

Anchors automatically replace the whole page, replicating client-side behaviour. The href will determine which page to fetch for swapping.

<body data-htswap>
	<nav>
		<a href="/login">Login</a>
		<a href="/signup">Sign Up</a>
		<a href="/contact">Contact</a>
	</nav>
	<main>
		<!-- Page content -->
	</main>
</body>

They can be further enhanced by adding data-htswap on each of them and giving it a target, determining which element to swap dynamically, rather than using the whole page.

<div>
	<nav>
		<a href="/posts" data-htswap="#content">All Posts</a>
		<a href="/posts?category=tech" data-htswap="#content">Tech</a>
		<a href="/posts?category=design" data-htswap="#content">Design</a>
	</nav>
	<main id="content">
		<!-- Post list -->
	</main>
</div>

Since data-htswap uses the closest parent selector, you can set it once on a parent instead of repeating it on each child:

<div>
	<!-- All these anchors will inherit data-htswap="#content" -->
	<nav data-htswap="#content">
		<a href="/posts">All Posts</a>
		<a href="/posts?category=tech">Tech</a>
		<a href="/posts?category=design">Design</a>
	</nav>
	<main id="content">
		<!-- Post list -->
	</main>
</div>

All swapping operations work with browser history, and navigating backward will swap back to the previous content, without a reload.

Forms are also automatically enhanced and support targetting. And they will add their inputs as URL or body params when swapping, allowing the server to take actions according to the current state of the form.

<div>
	<form action="/search" data-htswap="#results" method="get">
		<input type="text" name="q" placeholder="Search articles...">
		<select name="category">
			<option value="">All Categories</option>
			<option value="news">News</option>
			<option value="reviews">Reviews</option>
		</select>
		<button type="submit">Search</button>
	</form>
	<div id="results">
		<!-- Article list -->
	</div>
</div>

For an extensive coverage, see the features wiki page.

❓ Why?

With this section being personal reasoning, I'll first go through similar libraries/scripts, detailing what I don't like about them:

  • Swap.js: 450b gzipped, no form support, no history or merge modes. This was actually the inspiration for htswap, but it needed modernization and more features.
  • Alpine-AJAX: 3.59kb gzipped, requires Alpine.js to work which adds ~15kb. Great if you're already using Alpine, but that's an 18kb total commitment for just AJAX swapping.
  • HTMZ: 166b gzipped, clever iframe hack but has a noticeable delay on first click, no history or merge modes. Links are broken when JS is turned off, rather than working normally.
  • HTMX: 14-16kb gzipped, powerful but too large for my needs, encourages non-semantic patterns like making divs and buttons trigger requests instead of using proper anchors/forms.
  • zjax: 4.9kb gzipped, bundles client-side interactivity which I want to handle separately, overrides native anchor/form behaviors rather than progressively enhancing them.
  • data-star: 10.68kb gzipped, ambitious reactive framework but too heavy, treats forms as an afterthought with its signals-first approach, requires buying into its entire paradigm.

Your use case or preference might align with one of the above, but I needed htswap, which:

  • Doesn't exceed 2kb (gzipped) in size.
  • Doesn't include anything beyond anchor/form enhancements.
  • Doesn't break existing anchor/form functionality when JS is disabled.
  • Doesn't impose opinions about client-side interactivity.
  • Doesn't require users to have JavaScript for basic functionality.
  • Doesn't depend on any other library.
  • Doesn't care about your backend technology.

This is obviously subject to change as htswap reaches v1, and more can be integrated from the excellent alternatives mentioned above.