Browser Extension · Developer Tools · 2024
EasyType
A browser extension that strips friction out of typing — smart expansions and inline assists, everywhere you already work.
DRAG TO ROTATE
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,textareaandcontenteditable, 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
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
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.