Browser Extension · Developer Tools · 2024

EasyType

A browser extension that strips friction out of typing — smart expansions and inline assists, everywhere you already work.

TypeWeb / Extension
StatusLive
RoleSolo · End-to-end
StackJS · Chrome APIs
EASYTYPE
DRAG TO ROTATE
Drag to inspect

01Problem & Context

Repetitive typing is a tax everyone pays and nobody notices — the same phrases, addresses, snippets and corrections, retyped hundreds of times a day across every text field on the web.

The challenge: deliver text acceleration that works in any input — a Gmail compose box, a code review comment, a CRM note — without asking the user to configure anything or leave the page they're on.

Constraints: browser extensions run in a hostile, sandboxed environment. The solution had to be fast enough to feel invisible, respect the page's own keyboard handling, and never break the site it lives inside.

02Solution & Approach

I built EasyType as a content-script-first extension: the logic lives where the text does. Expansions are matched on keystroke against a local trie so lookups stay O(key length) regardless of how many snippets exist.

  • Zero-config by default — sensible expansions work the moment it's installed; power users layer their own on top.
  • Field-agnostic insertion — a single abstraction handles input, textarea and contenteditable, including rich editors that intercept the DOM.
  • Non-destructive — EasyType listens, never hijacks; if the host page wants a key, it gets it.

Why these choices: the trie keeps the hot path cheap, and the insertion abstraction is the difference between "works in a demo" and "works on the real, messy web."

03Visual Showcase

Screenshots of the extension UI and a usage demo. Replace the placeholders below with the real hero shot, feature breakdown, and demo GIF.

04Technical Breakdown

LangJavaScript PlatformChrome Extension (MV3) APIschrome.storage · scripting DataLocal trie index

The matcher is the interesting part — a prefix trie walked on each keystroke, with a debounce window so it never blocks input:

// match the longest snippet ending at the caret
function matchAtCaret(buffer, trie) {
  let node = trie, hit = null;
  for (let i = buffer.length - 1; i >= 0; i--) {
    node = node.children[buffer[i]];
    if (!node) break;
    if (node.expansion) hit = node.expansion;
  }
  return hit;  // expand only on an explicit trigger key
}

Hardest challenge: contenteditable surfaces each normalize text differently. The fix was to operate on Selection/Range rather than raw string splicing, so the caret lands correctly every time.

05Results & Impact

<1ms
Match latency / key
Any
Field type supported
0
Config to start

What I learned: the web is not a clean platform, and the value of a tool like this is almost entirely in how gracefully it handles the edge cases nobody demos.

What I'd do differently: ship sync earlier — people want their snippets to follow them across machines, and I underestimated that pull.

Want to build something like this?

Start a conversation