linkifyjs
A fast, plugin-extensible library that finds URLs, email addresses, hashtags, and mentions in plain text and converts them into HTML links.
Repository Health
Technical Analysis
linkifyjs is a JavaScript library that scans plain text for links — URLs, email addresses, hashtags, mentions, and IP addresses — and converts them into HTML <a> tags. Rather than relying on a single sprawling regular expression, it builds two purpose-built finite-state machines: a character-level scanner that tokenizes raw text, and a token-level parser that recognizes higher-level link structures from that token stream.
The core linkifyjs package has zero runtime dependencies and ships at roughly 20kB minified. It exposes a small API — find, test, and tokenize — that other packages in the monorepo build on: linkify-html and linkify-string render plain HTML or text output, linkify-react and linkify-element integrate with component-based UIs, and linkify-jquery wires it into jQuery-based pages. A plugin system (registerTokenPlugin / registerPlugin) lets consumers extend the shared state machine to recognize additional token types — hashtags, @mentions, #-tickets, keywords, and IP addresses are all implemented as separate plugin packages rather than baked into the core.
linkifyjs has been maintained since 2013 and is widely used as the auto-linking engine inside larger editor and rich-text projects (including Tiptap/ProseMirror-based editors), where reliable, extensible link detection in user-typed text is a recurring requirement.
What You Get
- A dependency-free core (
linkifyjs) exposingfind,test, andtokenizefor detecting links in any string - Companion interface packages —
linkify-html,linkify-string,linkify-react,linkify-element,linkify-jquery— for rendering detected links in different environments - A plugin system (
registerTokenPlugin/registerPlugin) for extending recognition to hashtags, @mentions, #-tickets, keywords, and IPs without touching core scanning logic - Fine-grained formatting options (
defaultProtocol,target,rel,className,attributes, customrender) for controlling how detected links are rendered - Built-in, alphabetically-organized top-level-domain data compressed via a custom trie encoding to keep bundle size small
Common Use Cases
- Auto-linking URLs and email addresses inside user-generated text such as comments, chat messages, or posts
- Powering the auto-link feature of rich-text and WYSIWYG editors built on ProseMirror/Tiptap-style architectures
- Highlighting #hashtags and @mentions in social-style feeds and messaging UIs
- Validating whether a string is a well-formed URL or email address via
linkify.test() - Rendering safe, customizable
<a>tags from untrusted plain text without hand-writing detection regexes
Under The Hood
Architecture
linkify.mjs orchestrates a two-stage pipeline built on the generic finite-state-machine primitives in fsm.mjs (the State class with tt/tr/ts transition builders). scanner.mjs constructs a character-level FSM that walks a lowercased copy of the input string and emits a flat token stream (run() in scanner.mjs); parser.mjs then builds a second FSM over that token stream, using multi.mjs’s MultiToken subclasses to recognize composite structures such as URLs and email addresses. Plugins registered via registerTokenPlugin/registerPlugin are queued in an internal INIT object and, when init() first runs (lazily, on first call to tokenize), are given direct access to the scanner and parser state machines to graft in new token types and transitions. options.mjs is a separate presentational layer — an Options class that resolves per-type or callback-based formatting (format, render, validate, etc.) — cleanly decoupling detection from rendering. Because every interface package (linkify-html, linkify-react, linkify-jquery, …) depends on the same shared State machinery and INIT singleton, a change to the core FSM contract in fsm.mjs would ripple through the entire monorepo.
Tech Stack
The core linkifyjs package is plain ESM JavaScript ("type": "module") with zero runtime dependencies. The monorepo is managed with native npm workspaces (no Lerna/Turborepo), built with Rollup (via a shared root rollup.config.js) and Babel for down-level browser compatibility, and packaged as CJS/ESM dual output (dist/linkify.cjs / dist/linkify.mjs). There is no TypeScript source — instead, tsc runs in declaration-only mode (emitDeclarationOnly) against the built JS to generate .d.ts files from JSDoc annotations. Documentation for consumers lives on a separately hosted docs site (linkify.js.org) rather than in-repo.
Code Quality
Each workspace package has a corresponding .test.mjs file under test/spec/, written with Mocha, Chai, and Sinon; browser-level integration is verified via Karma against Chrome, Firefox, and BrowserStack, with QUnit-based specs. Coverage is tracked with c8/nyc and reported to Coveralls, with the README’s badge advertising roughly 99% coverage. CI (GitHub Actions) runs a lint gate before a unit-test matrix across four Node.js versions (20/22/24/26), followed by a separate coverage and cross-browser integration job. Error handling is explicit: public API functions like registerTokenPlugin and registerCustomProtocol throw descriptive, library-prefixed Error objects on invalid input rather than failing silently. There is no compile-time type system, only JSDoc-derived types and runtime validation, and ESLint (flat config) plus Prettier are enforced in CI.
What Makes It Unique
Instead of a single large regular expression, linkifyjs implements link detection as two composable, hand-rolled finite-state machines with a genuine plugin architecture: third-party or first-party plugins literally extend the shared state graph to recognize new token types (hashtags, mentions, tickets) without forking or patching the core scanner or parser. It also keeps its footprint small despite covering hundreds of top-level domains by encoding the TLD list as a compact trie-like string (encodedTlds) that’s decoded once at initialization rather than shipped as a large literal array or matched via a sprawling regex alternation.
Used by 16 apps in this directory
Docmost
Productivity · Note Taking · Collaboration
Self-hosted collaborative wiki and knowledge base with real-time editing, diagrams, AI assistance, and enterprise access controls — a modern alternative to Confluence and Notion.
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Element Web
Team Chat · Collaboration
A polished, self-hostable Matrix client for secure, decentralized messaging and collaboration that puts your organization in full control of its data.
Element Web
Team Chat · Collaboration
A polished, self-hostable Matrix client for secure, decentralized messaging and collaboration that puts your organization in full control of its data.
Element Web
Team Chat · Collaboration
A polished, self-hostable Matrix client for secure, decentralized messaging and collaboration that puts your organization in full control of its data.
Element Web
Team Chat · Collaboration
A polished, self-hostable Matrix client for secure, decentralized messaging and collaboration that puts your organization in full control of its data.
Flowise
Developer Tools · Automation · No Code Platforms
Drag-and-drop visual builder for AI agents, RAG pipelines, and multi-agent systems—deploy anywhere in minutes.
Kaneo
Product Management · Productivity · Project Management
Lightweight self-hosted project management that gives you kanban boards, GitHub sync, and full team collaboration without the enterprise bloat.