Between hand-written DOM code (The Window Object-DOM Patterns and Performance) and a full framework (Front-End Frameworks) sits a group of small libraries that each solve one problem well, all usable from a plain <script> tag. The sizes below were measured from each project's minified CDN build with gzip -9 in September 2026.
| Library | Model | Gzipped | Licence | Repository |
|---|---|---|---|---|
| jQuery 4.0.0 | Imperative wrapper | 27.4 KB | MIT | github.com/jquery/jquery |
| Cash 8.1.5 | jQuery-style subset | 6.3 KB | MIT | github.com/fabiospampinato/cash |
| Alpine.js 3.17.3 208,904 | Reactive attributes | 19.9 KB | MIT | github.com/alpinejs/alpine |
| htmx 2.0.10 79,053 | HTML from the server | 16.5 KB | 0BSD | github.com/bigskysoftware/htmx |
| Lit 3.3.3 310,034 (core) | Web components | 6.1 KB | BSD-3-Clause | github.com/lit/lit |
| Preact 10.29.8 268,577 | Virtual DOM, React 7,897 API | 4.8 KB | MIT | github.com/preactjs/preact |
Cash
Cash keeps jQuery's chainable $() API for selection, classes, attributes, CSS, events (with delegation) and .serialize(), but its build contains no effects, AJAX or Deferreds (its README says full parity is not a goal): use CSS transitions, fetch() and Promises instead. To shrink a legacy site, swap the script tag, run the pages, and replace the missing calls with the native equivalents from jQuery to Vanilla JS. Install with npm 2,036 install cash-dom; the latest npm release, 8.1.5, dates from April 2023.
<script src="https://cdn.jsdelivr.net/npm/cash-dom@8.1.5/dist/cash.min.js"></script>
<ul id="list" style="font:16px sans-serif; margin:0"><li>Desk lamp</li><li>Clip light</li></ul>
<pre id="log" style="margin:0"></pre>
<script>
$('#list').on('click', 'li', (e) => $(e.target).toggleClass('picked').css('color', '#2e7d32'))
.append('<li>Floor lamp</li>');
$('#list li').last().trigger('click');
$('#log').text(`picked: ${$('.picked').text()}, items: ${$('#list li').length}\n` +
`fadeIn: ${typeof $.fn.fadeIn}, ajax: ${typeof $.ajax}, Deferred: ${typeof $.Deferred}`);
</script>
Alpine.js and htmx
Both put behavior in HTML attributes; HTML Tooling and Libraries builds a complete example with each. Alpine.js keeps state on the client: x-data objects become reactive proxies built on @vue/reactivity, its only dependency, and a MutationObserver initializes components added later. htmx keeps state on the server: attributes such as hx-get and hx-swap fetch HTML fragments and swap them into the page. They combine well, htmx for data and Alpine.js for local UI state such as open menus.
Lit and Preact
Both render components (Front-End Frameworks compares them with larger frameworks). Lit builds standard custom elements (Web Components): an ` html... tagged template is parsed once into a <template>, and later renders update only the ${} holes, with no virtual DOM. Preact implements React's component and hooks API over a small virtual DOM; preact/compat` lets most React libraries run unchanged.
Choosing
Pick htmx or Alpine.js to enhance server-rendered pages, Cash to slim down jQuery code, Lit for widgets that must work inside any framework, and Preact when you want React's model and ecosystem at a fraction of the size.