webdevpuneet.com

Regex Tester & Match Visualizer — Free HTML CSS JS Snippet

Regex Tester & Match Visualizer · Dev · Plain HTML, CSS & JS · Live preview

Category🛠 Dev

Copy & paste

Source Code

<div class="wrap">
  <h2>Regex Tester</h2>

  <div class="pattern-row">
    <span class="slash">/</span>
    <input type="text" id="pattern-input" spellcheck="false" value="(\w+)@(\w+)\.com" placeholder="pattern" />
    <span class="slash">/</span>
    <input type="text" id="flags-input" spellcheck="false" value="g" placeholder="flags" class="flags" />
  </div>
  <div class="flag-toggles">
    <label><input type="checkbox" data-flag="g" checked /> g global</label>
    <label><input type="checkbox" data-flag="i" /> i ignore case</label>
    <label><input type="checkbox" data-flag="m" /> m multiline</label>
    <label><input type="checkbox" data-flag="s" /> s dotAll</label>
  </div>

  <div class="status" id="status-line">Valid pattern</div>

  <textarea id="test-input" spellcheck="false" placeholder="Test string...">Contact us at [email protected] or [email protected] for help.</textarea>

  <div class="highlight-label">Live matches</div>
  <div class="highlight-box" id="highlight-box"></div>

  <div class="matches-label">Match details <span id="match-count"></span></div>
  <div class="matches-list" id="matches-list"></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Uses the real browser RegExp engine — no simulated or approximated matching logic
Live syntax validation via try/catch around new RegExp(), surfacing the real SyntaxError message
Flag checkboxes (g, i, m, s) and a raw flags text field stay bidirectionally in sync
Global flag is force-enabled internally for iteration while displaying the user's actual flag string
Zero-length match infinite-loop guard (advances lastIndex manually) plus a hard iteration cap
Alternating-color <mark> highlighting so adjacent or touching matches stay visually distinct
Full capture group breakdown per match, explicitly labeling non-participating optional groups
HTML-escaped rendering throughout so literal < and & in test text can never break the output

About this UI Snippet

Regex Tester — Live JavaScript RegExp Matching with Highlighted Matches & Capture Groups

Screenshot of the Regex Tester & Match Visualizer snippet rendered live

Regular expressions are notoriously hard to read back once written, and the fastest way to understand what a pattern actually matches is to see it highlighted against real text. This snippet is a real JavaScript regex engine test — every match shown is produced by the browser's native RegExp object running against whatever pattern and test string you type, not a simulated or approximated matcher.

Building the RegExp object safely

run() reads the raw pattern string and flags string, sanitizes the flags with flags.replace(/[^gimsuy]/g, '') to strip anything that isn't a real JavaScript regex flag, and wraps construction in a try/catch. An invalid pattern — unbalanced parentheses, a bad character class, an unsupported escape — throws a SyntaxError from the RegExp constructor itself, and the caught message is shown directly in the status line. This is real engine validation, not a hand-rolled regex syntax checker, so the error messages match exactly what you'd see in a browser console.

Forcing the global flag for iteration, without changing displayed intent

To collect *all* matches rather than just the first, the exec loop needs the g flag set internally regardless of whether the user's flag string includes it — otherwise RegExp.exec() always returns the same first match forever, since without g it doesn't advance lastIndex. The snippet handles this by constructing the working regex with flags.includes('g') ? flags : flags + 'g', so iteration always works, while the status line still displays the flags exactly as the user entered them for accuracy. The classic infinite-loop trap with zero-length matches (a pattern like x* matching an empty string) is guarded against explicitly: if (m.index === re.lastIndex) re.lastIndex++, which forces the engine to advance past a zero-width match instead of looping forever at the same index — combined with a hard 500-iteration cap as a second line of defense.

Building the highlighted view without a virtual DOM

The highlight box is built by walking the matches in order and slicing the original text between them: everything from the cursor position up to the next match's .index is escaped and appended as plain text, then the matched substring itself is wrapped in a <mark>, alternating a CSS class between two colors so adjacent matches remain visually distinguishable even when they're touching. escapeHtml() is applied to every literal text slice before insertion — including inside the <mark> — so a test string containing literal < or & characters can never break the rendered markup or, worse, get interpreted as HTML.

Capture groups shown per match

Each match object from exec() is an array where index 0 is the full match and indices 1+ are capture groups in pattern order; match.length > 1 signals the pattern actually has capture groups. The per-match detail row lists each group's value, explicitly labeling an unmatched optional group as (undefined) rather than silently omitting it — an easy source of confusion when a pattern has an optional group like (foo)? that sometimes doesn't participate in a given match.

Step by step

How to Use

  1. 1
    Type a pattern between the slashesThe pattern field accepts standard JavaScript regex syntax without the surrounding slashes — they're shown as static decoration.
  2. 2
    Toggle flags with the checkboxes or the flags fieldg (global), i (ignore case), m (multiline), and s (dotAll) can be set either by checkbox or by typing directly into the flags input — both stay in sync.
  3. 3
    Edit the test stringMatches update live on every keystroke in the textarea, no submit button required.
  4. 4
    Read the highlighted viewMatched substrings are wrapped in alternating-colored marks directly in the test text, so you can see exactly what the pattern captured in context.
  5. 5
    Check the match details listEach match shows its start index, matched text, and every capture group's value below the highlighted view.
  6. 6
    Watch the status line for syntax errorsAn invalid pattern shows the real JavaScript SyntaxError message from the RegExp constructor instead of silently failing.

Real-world uses

Common Use Cases

Building and debugging validation regexes
Iterate on an email, phone number, or slug validation pattern against a batch of real and edge-case test strings before dropping it into form validation code.
Teaching regex syntax and capture groups
Show students exactly which part of a pattern matches which part of the text by toggling flags and watching the highlighted output change in real time.
Writing a find-and-replace or parsing script
Confirm a pattern captures the right groups before wiring it into a String.replace() callback or a log-parsing script — the group breakdown shows exactly what each () will extract.
Internal developer tooling
Pair with a text diff checker or JSON diff viewer in an internal dev-tools page for quick data-cleaning and pattern-matching tasks.
Reviewing a teammate's regex in code review
Paste a pattern from a pull request along with representative input data to quickly confirm it behaves as the author intended before approving.
Related: CIDR / Subnet Calculator
See the CIDR / Subnet Calculator for a related dev pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

It uses the browser's native JavaScript RegExp object directly — new RegExp(pattern, flags) followed by real .exec() calls. Every match, capture group, and error message you see is exactly what the same pattern would produce in any JavaScript environment.

Without the global flag, RegExp.exec() always returns the same first match and never advances, making it impossible to iterate through multiple matches. The tool internally appends g for the iteration loop while still displaying your actual chosen flags in the status line, so what you see reflects your real pattern configuration.

A pattern like x* can match a zero-length string, which would otherwise leave lastIndex unchanged and loop forever. The exec loop checks if (m.index === re.lastIndex) and manually increments lastIndex in that case, forcing the engine past the zero-width match, plus a hard cap of 500 iterations as a safety backstop.

It means that specific group is part of the pattern but did not participate in this particular match — typically because it's inside an optional group like (foo)? that wasn't present in the matched text. JavaScript's match arrays represent this as undefined at that group's index, and the tool labels it explicitly rather than showing a blank.

Yes — any valid JavaScript regex syntax works, since the pattern is passed straight to the native RegExp constructor. Named groups appear in match.groups, though this tool's detail view currently lists groups by their numeric index rather than by name.

No. Everything runs client-side using the browser's built-in RegExp engine — nothing is transmitted to a server, so it's safe to test against real (non-sensitive) log lines or sample data.