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 🙏

© 2026 – Pkg Stats / Ryan Hefner

thaana-keyboard-lite

v0.1.5

Published

A tiny (~40 lines, zero dependencies) Thaana keyboard library for the web

Downloads

89

Readme

thaana-keyboard-lite ✨

A tiny (~80 lines, ~1 KB minified, zero dependencies) Thaana keyboard library for the modern web.

Live demos → — Vanilla JS, React, and Vue examples.

Why another Thaana keyboard?

There are several existing Thaana keyboard libraries for JavaScript. All of them were written in a different era of the web and carry baggage that makes them awkward to use in modern projects, so I wanted to make something that was easier to work with modern stacks and frontend frameworks.

thaana-keyboard (aharen) — No dependencies, TypeScript source. Uses a two-phase approach (beforeinput to capture + input to replace) with manual string splicing to swap characters. This breaks the browser's native undo/redo stack and requires careful cursor tracking. No ES module support, no cleanup API.

thaanaKeyboard (ajaaibu) — Requires jQuery and distributed through Bower. Same manual value replacement approach that breaks undo/redo. No IME or mobile keyboard support, no cleanup API.

JTK (jawish) — The most feature-rich of the three, with three keyboard layouts and per-element layout switching. Uses deprecated event APIs. No module system, no npm package, no IME support.

All three are awkward to use in modern projects. They share a common approach: intercept a key event, then manually replace the field's .value to swap in the Thaana character. But replacing .value resets the cursor to the end, so they all need manual bookkeeping — save cursor position, splice the string, restore cursor, handle selections. This also breaks the browser's native undo/redo stack, since the browser sees a programmatic value change rather than a user edit. None of them offer ES module exports, element ref support, or cleanup functions — things you need for clean integration with modern frameworks.

That said, huge thanks to aharen, ajaaibu, and jawish for their pioneering work. They solved a real problem for the Dhivehi developer community and this library builds directly on the foundation they laid.

Design

thaana-keyboard-lite ✨ leans on the modern web platform instead of working around it. Two small listeners do the work:

  • beforeinput intercepts ordinary Latin keypresses and inserts the Thaana character via execCommand('insertText'). The browser keeps owning the cursor, selection, scroll, and the native undo/redo stack — no manual bookkeeping.
  • input runs a stateless repair sweep — scan the value, swap any mapped Latin character for its Thaana equivalent, restore the caret. This handles the cases beforeinput can't cleanly cancel: Android IME committing the composition buffer on space, paste, and drag-and-drop.

The field's own value is the source of truth. There's no shadow state to keep in sync, no class instance to manage, and no global listeners attached to document.

This means:

  • Tiny — ~80 lines of source, ~1 KB minified, zero dependencies
  • Composition / IME support — works with mobile keyboards
  • Undo/redo preservedexecCommand participates in the browser's native history
  • Selection replacement, RTL caret, scroll — handled by the browser, not us
  • Framework-friendly — ESM, element refs, returns a cleanup function for useEffect

Install

npm install thaana-keyboard-lite

Usage

Add the class to your inputs or textareas:

<input type="text" class="thaana-keyboard" dir="rtl" />
<textarea class="thaana-keyboard" dir="rtl"></textarea>

Then call:

<script src="thaana-keyboard-lite.js"></script>
<script>
  thaanaKeyboard();
</script>

Or as an ES module:

import { thaanaKeyboard } from "thaana-keyboard-lite";
thaanaKeyboard();

With a custom selector:

thaanaKeyboard({ selector: "#my-thaana-input" });

Or multiple selectors:

thaanaKeyboard({ selector: ["#name", "#address", ".dhivehi"] });

You can also pass DOM elements directly and get a cleanup function back — useful for frameworks like React:

const ref = useRef(null);

useEffect(() => {
  return thaanaKeyboard({ element: ref.current });
}, []);

return <input ref={ref} dir="rtl" />;

thaanaKeyboard() returns a function that removes all event listeners, so it works as a useEffect cleanup out of the box. None of the existing Thaana keyboard libraries support this.

Examples

Working examples for each integration live in examples/:

To preview locally, build them and serve the output:

bun run build:examples
bunx serve dist/examples

Why plain JS with JSDoc instead of TypeScript?

The library ships as a single .js file. No build step, no transpilation — what you see in the repo is exactly what runs in the browser and what gets published to npm. JSDoc gives us type checking during development (via tsc --checkJs or editor support) without adding a compile step or requiring consumers to deal with .d.ts files, source maps, or a dist/ folder.

Keymap

Standard Dhivehi phonetic layout. Lowercase, uppercase, and punctuation — 62 mappings total. Brackets and parentheses are swapped for RTL.

License

MIT