Regex Tester & Match Visualizer — Free HTML CSS JS Snippet

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

Share & Support

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.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's JavaScript into an AI assistant like Claude and ask it to explain exactly why the zero-length-match guard (if (m.index === re.lastIndex) re.lastIndex++) is necessary — it's the kind of edge case that causes a naive regex-iteration loop to freeze a tab. It's also a solid base to extend: ask for named capture group support (reading match.groups instead of numeric indices), a "common patterns" dropdown (email, URL, IPv4, hex color) to load as starting points, or a replace-preview mode that shows the result of String.replace() with a user-supplied replacement string.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a live regex tester in plain HTML, CSS, and JavaScript, no libraries.

Requirements:
- A pattern input and a flags input (plus optional checkboxes for g, i, m, s that stay synced with the flags text), and a test-string textarea, all updating results live on every keystroke.
- Construct the actual RegExp object from the user's pattern and flags inside a try/catch, and display real JavaScript SyntaxError messages inline when the pattern is invalid, rather than silently failing.
- Regardless of whether the user's flags include g, internally force it on for the matching loop so all matches (not just the first) are collected, while still showing the user's actual entered flags in the UI.
- Guard against infinite loops on patterns that can match a zero-length string by manually advancing lastIndex when a match's index doesn't move it forward, plus a hard iteration cap as a backstop.
- Render the test string with every match wrapped in a highlighted <mark> element, alternating between two colors so consecutive or adjacent matches remain visually distinguishable, with all literal text properly HTML-escaped.
- Below the highlighted text, list every match with its start index, matched substring, and the value of every capture group (explicitly showing when an optional group didn't participate in that match).

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

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.