← Back to Awesome

Sections

Tiny JS

GitHub repository ↗ synced 2026/8/9

Awesome Tiny JS Awesome

Tiny front-end libraries to put your bundle on a diet. Rules:

  • Size is under 2 kB-ish, min + gzip, with all dependencies, except where noted.
  • For multi-purpose libraries, the size of a useful subset must be under 2 kB-ish.
  • Useful client-side. I haven't figured out participation rules for node-only libraries, and I'm not too worried about them.
  • Second-level libraries only allowed for React, Vue, Angular, svelte.
  • 100+ GitHub stars or 500+ weekly npm installs to focus on tools with some community review.
  • No zero-JS (CSS- or type-only) libraries. It's not awesome-css or something.

UI Frameworks

preact

React-like API (pre-hooks). Cool ecosystem of similarly tiny tools and components. Highly recommended. <img align="top" height="24" src="./img/preact.svg">

hyperapp

vDOM framework with pure JS syntax and immutable state, <img align="top" height="24" src="./img/hyperapp.svg">

redom

Hyperapp-style templates with _imperative_ event listeners and updates, <img align="top" height="24" src="./img/redom.svg">

fre

React-like library with hooks and concurrency, <img align="top" height="24" src="./img/fre.svg">

van

vDOM-based framework optimized for no-build setups, <img align="top" height="24" src="./img/vanjs-core.svg">

superfine

Hyperapp with state & effect hooks removed, <img align="top" height="24" src="./img/superfine.svg">

arrowjs

Tagged templates + reactive data, <img align="top" height="24" src="./img/arrow-jscore.svg">

umbrella

jQuery-style DOM manipulation library, <img align="top" height="24" src="./img/umbrellajs.svg">

UI frameworks (libraries?) provide declarative templates, event bindings, and observable state to update the view. I've been generous and expanded the size limit for this category to 4.5 kB (if you're boring, count them as 2 libraries), but also increased the star limit to 2K.

The following libraries are small and cool, but note they're about 500x less popular than preact. Kudos for deconstrucing the very essence of a "framework":

Now, for the openly experimental UI libraries:

And if being declarative is not your thing:

Event Emitters

mitt

Plain event emitter that I use on most projects, <img align="top" height="24" src="./img/mitt.svg">

nanoevents

Nicer unsubscribe API, but no `*` event, <img align="top" height="24" src="./img/nanoevents.svg">

onfire.js

Also has `.once` method, <img align="top" height="24" src="./img/onfirejs.svg">

Event emitter pattern is fairly easy to implement yourself, but why bother when you have these cool tools? With an arms race to build the smallest one, the limit is 0.5 kB.

State Managers

zustand

Simple stores with pleasant actions and selectors. Vanilla <img align="top" height="24" src="./img/zustandvanilla.svg">, React <img align="top" height="24" src="./img/zustand.svg">

nanostores

Modular store with good tree-shaking support, <img align="top" height="24" src="./img/nanostores.svg"> vanilla, + React <img align="top" height="24" src="./img/nanostoresreact.svg"> extra. Supports all the top frameworks.

exome

Atomic stores with lots of framework connectors, <img align="top" height="24" src="./img/exome.svg"> + React <img align="top" height="24" src="./img/exomereact.svg"> extra. Supports all the top frameworks.

storeon

Minimal redux-styled store with lots of framework connectors, <img align="top" height="24" src="./img/storeon.svg">. React extra <img align="top" height="24" src="./img/storeonreact.svg"> + Vue, Svelte, Angular.

unistore

Centralized store with actions, <img align="top" height="24" src="./img/unistore.svg"> + React <img align="top" height="24" src="./img/unistorereact.svg">

teaful

Store with useState-like API, <img align="top" height="24" src="./img/teaful.svg">, including React / preact connector.

State managers combine observable state with actions and framework bindings, intended for app-wide state.

Signals

@preact/signals

The OG signals from preact <img align="top" height="24" src="./img/preactsignals-core.svg"> core, <img align="top" height="24" src="./img/preactsignals-react.svg"> with react integration.

usignal

A smaller signal implementation, <img align="top" height="24" src="./img/usignal.svg">

hyperactiv

4 functions to make objects observable and listen to changes, <img align="top" height="24" src="./img/hyperactiv.svg">

flimsy

Signals from Solid (it _almost_ fit into UI frameworks category itself). Author warning: _it's probably buggy._ <img align="top" height="24" src="./img/flimsy.svg">

A signal-styled state manager provides observable values (aka signals), derived values and effects.

Honorable mention: oby could make it if it had tree-shaking, but otherwise is around 7 kB.

Reactive Programming

flyd

Rx-styled event streams, <img align="top" height="24" src="./img/flyd.svg">

callbag-basics

Rx-style event streams, <img align="top" height="24" src="./img/callbag-basics.svg">

Another well-known state management approach is reactive programmning — operating on event streams, applying filters and transforms to end up with an observable value. Think RxJS, but tiny:

Routers and URL Utils

wouter

Declarative router for React / preact, <img align="top" height="24" src="./img/wouter.svg">, also available as a standalone hook: <img align="top" height="24" src="./img/wouteruse-browser-location.svg">

@nanostores/router

Routes as a nanostores store (framework-agnostic), <img align="top" height="24" src="./img/nanostoresrouter.svg">

navaid

History-based observable router, <img align="top" height="24" src="./img/navaid.svg">

matchit

Route parser and matcher in <img align="top" height="24" src="./img/matchit.svg">

regexparam

Convert path to regexp in <img align="top" height="24" src="./img/regexparam.svg">

qss

Parse querystrings in <img align="top" height="24" src="./img/qss.svg">. Not sure you need it, [URL API](https://developer.mozilla.org/en-US/docs/Web/API/URL) support is good.

Do stuff on URL / history changes, with path matching and parsing:

Just want to parse or match URL paths without observing them? Here you go:

API Layer

redaxios

Drop-in axios replacement for modern browsers, <img align="top" height="24" src="./img/redaxios.svg">

wretch

Chainable API with error processing and lots of extra plugins, <img align="top" height="24" src="./img/wretch.svg">

gretchen

Chainable API with type-safe errors, <img align="top" height="24" src="./img/gretchen.svg">

unfetch

Loose fetch polyfill, <img align="top" height="24" src="./img/unfetch.svg">

fetch API has some boilerplate associated with it: serialize & parse data, reject on non-200 response, etc. These tiny packages handle it for you:

If for some reason you still need a fetch polyfill, try this one:

I18N

@nanostores/i18n

Detect locale, load dictionaries, format dates / numbers, <img align="top" height="24" src="./img/nanostoresin.svg"> including nanostores.

eo-locale

Interpolation and dates / numbers, <img align="top" height="24" src="./img/eo-localecore.svg">, or <img align="top" height="24" src="./img/eo-localereact.svg"> with react bindings.

rosetta

Bare-bones template strings (`{{hello}}, {{username}}`) and custom functions for everyting else, <img align="top" height="24" src="./img/rosetta.svg">

lingui

Small core with template strings, <img align="top" height="24" src="./img/linguicore.svg">

A map of strings might seem enough to translate an app, but these tools also handle interpolation and some extra goodies:

Dates and Time

date-fns

Not tiny as a whole, but [most functions](https://bundlephobia.com/package/date-fns) are under 1 kB each (format and parse are quite heavy).

dayjs

_Almost_ moment.js-compatible API, covers most use cases, <img align="top" height="24" src="./img/dayjsesm.svg">

tinytime

Simple date / time formatter: `{h}:{mm} -> 9:33`, <img align="top" height="24" src="./img/tinytime.svg">

tinydate

Date / time formatter, only supports padded numeric output (`September -> 09`), <img align="top" height="24" src="./img/tinydate.svg">

time-stamp

More of the same, <img align="top" height="24" src="./img/time-stamp.svg">

ms

Parse & format ms durations, e.g. `"1m" <-> 60000`, <img align="top" height="24" src="./img/ms.svg">

timeago.js

Format dates into stuff like _X minutes ago_ or _in X hours,_ <img align="top" height="24" src="./img/timeagojs.svg">

fromnow

More of the same, <img align="top" height="24" src="./img/fromnow.svg">

Date and time manipulation in pure JS is verbose. Luckily, two of the top date libraries have sensible size:

And some more packages that only do formatting:

Note that the built-in Intl.DateTimeFormat has decent support.

Generic Utilities

remeda

90 tree-shakable helpers [(list).](https://bundlephobia.com/package/remeda)

rambda

187 tree-shakable helpers [(list).](https://bundlephobia.com/package/rambda)

just

82 helpers in separate packages [(list).](https://anguscroll.com/just/)

@fxts/core

96 tree-shakable helpers. Lazy evaluation support.

Something you'd find in lodash or ramda, but smaller. Most are pretty similar and very small, with minor differences in package structure (single / package-per-helper) and tree shaking vs direct helper import.

Honorable mention: underscore, contains many sub-1 kB helpers. It does not tree-shake as well as the libraries above due to codebase structure.

Note: lodash itself is not tree-shakable, but has made many attempts at modulaity with lodash.method packages, imports from lodash/method, and lodash-es, none of which work well in practice.

Also note that much of the original lodash functionality comes built-in with modern ES. Prefer native versions over libraries as your browser target allows.

Validation

v8n

zod-style API with fine-grained checks: `v8n().string().minLength(5).first("H").last("o")`. No tree shaking, <img align="top" height="24" src="./img/vn.svg">

banditypes

The smallest validation library: <img align="top" height="24" src="./img/banditypes.svg">

superstruct

The most popular modular validation library with good tree-shaking, <img align="top" height="24" src="./img/superstruct.svg">

valibot

Another modular validation library, <img align="top" height="24" src="./img/valibot.svg">

deep-waters

Composable functional validators, <img align="top" height="24" src="./img/deep-waterscompose-deep-watershasShape-deep-watersarrayOf-deep-watersisString-deep-watersisNumber-deep-watersisBoolean.svg">.

To check if an object matches an expected schema, you'd often use zod, yup, joi or ajv. But 90% of the time you can get what you need in under 2 kB. Note: I compare a base validation subset (core + object / array + string / number / boolean) under tree-shaking to avoid punishing libs that have more features.

Unique ID Generation

@lukeed/uuid

Real UUIDs, <img align="top" height="24" src="./img/lukeeduuid.svg">

nanoid

Random IDs with larger alphabet, <img align="top" height="24" src="./img/nanoid.svg">

uid

More of the same, <img align="top" height="24" src="./img/uid.svg">

hexoid

Hexadecimal IDs, <img align="top" height="24" src="./img/hexoid.svg">

Unique ID generation does not take a lot of code, but it's not someting I'd want to write myself. Limit is 500 bytes. Also note that the native crypto.randomUUID has OK support.

Colors

colord

Manipulate colors and convert between spaces, <img align="top" height="24" src="./img/colord.svg">. Extra features come as plugins, 150b to 1.5 kB each.

colr

More of the same, <img align="top" height="24" src="./img/colr.svg" >

polychrome

More of the same, <img align="top" height="24" src="./img/polychrome.svg">

randomcolor

Attractive random colors with configuration. <img align="top" height="24" src="./img/randomcolor.svg">

Color manipulation is rare in pure UI development, but very helpful for data visualization, and uses freaky math. Don't fry your brain, take these:

Touch Gestures

alloyfinger

Pan, swipe, tap, doubletap, longpress, _and_ pinch / rotate. My personal favorite. <img align="top" height="24" src="./img/alloyfinger.svg">.

tinygesture

Configurable pan, swipe, tap, doubletap, longpress. <img align="top" height="24" src="./img/tinygesture.svg">.

pointer-tracker

Unified interface for mouse, touch and pointer events, <img align="top" height="24" src="./img/pointer-tracker.svg">

detect-it

Detect present and primary input method (touch / mouse) and supported events, <img align="top" height="24" src="./img/detect-it.svg">

Touch gestures like swipe, drag, pinch or doubletap are a staple of mobile UX, but recognizing a series of touchmove / pointer events as a gesture is tricky, and testing is painful. Here are two libraries that do the heavy lifting for you:

Even if you want to detect gestures yourself, juggling mouse, touch and pointer events is hard enough, and browser inconsistencies don't help. Here are two more libraries to assist with that:

Honorable mentions: any-touch attempts a modular approach to gesture detection, but the core is around 2 kB without any gesture recognizers. rc-gesture, used in ant design system, could be the only react component on the list, but babel-runtime / corejs polyfills hard-wired into the build push the ~2.5 kB size to over 10 kB.

Text Search

js-search

Feature-rich and customizable: multi-field indices, stop words, custom stemmers and tokenizers. <img align="top" height="24" src="./img/js-search.svg">

ndx

Similar to js-search, differs in [ranking](https://kmwllc.com/index.php/2020/03/20/understanding-tf-idf-and-bm-25/) and is less strict for multi-word queries [(compare)](https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=js-search,ndx,Wade&search=twilight%20sag). Supports field weights. <img align="top" height="24" src="./img/ndx-ndxquery.svg">

wade

Also similar, [(compare)](https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=js-search,Wade,ndx&search=twilight%20sag) <img align="top" height="24" src="./img/wade.svg">

libsearch

Index-free search (slower, but easier to use) with sane ordering <img align="top" height="24" src="./img/libsearch.svg">

stemmer

<img align="top" height="24" src="./img/stemmer.svg">

porter-stemmer

<img align="top" height="24" src="./img/porter-stemmer.svg">

Text search is important for client-side filtering and autosuggests. Naive option.includes(search) has no sensible order on the results, and ignoring word boundaries gives unexpected matches like spa -> newSPAper. First, here are some libraries that prioritize word matches:

One way to find sensible inexact matches is stemming — converting words to a root form. Walked will match walking, etc. Here are a few Porter stemmers for English language:

For non-English words, I only have honorable mentions: snowball-js is 17 kB with 15 languages, lunr-languages supports 30 languages but only works with lunr, the most promising one is natural but it depends on Node.js.

Fuzzy search

fuzzy

Index-free, can highlight matches. <img align="top" height="24" src="./img/fuzzy.svg">

fuzzy-search

With stateful index. <img align="top" height="24" src="./img/fuzzy-search.svg">

fzy.js

Matches one string at a time, tree-shakeable scores and match highlighting. <img align="top" height="24" src="./img/fzyjs.svg"> total, or ~150 bytes for `hasMatch` only.

fuzzysearch

One string at a time, does not compute score / rank. <img align="top" height="24" src="./img/fuzzysearch.svg">

liquidmetal

Quicksilver algorithm, prioritizes matches at start of word for command abbreviations (e.g. `gp` -> `git push`). One string at a time. <img align="top" height="24" src="./img/liquidmetal.svg">

quick-score

Another quicksilver-based lib, tweaked for long strings. Built-in list filtering and sorting, <img align="top" height="24" src="./img/quick-score.svg"> or 1.2 kB for single-string scoring.

fuzzyset

Find misspellings, e.g. missipissi -> Missisipi, <img align="top" height="24" src="./img/fuzzyset.svg"> Commercial usage costs $42.

Fuzzy search is another take on inexact matching — the words can be modified. First, we have libraries that only allow insertion: spacecat -> SPACECrAfT. Not perfect for general-purpose text search, but great for filename, command, or URL lookups.

Finally, one library is specifically built for spellchecking:

Footnotes

See WIP for possibly awesome libraries I have found, but not yet analyzed deeply, and incubate for awesome libraries that don't meet popularity criteria yet.

Collected and reviewed by Vladimir Klepov in 2023.