---
description: "Interactive regex tester with live match highlighting, named group extraction, and a library of common patterns. Pre-loaded with email, URL, UUID, and date patterns."
---

# Regex Playground

> **Purpose:** A live, interactive regular expression tester. Type a pattern on the left and watch matches highlight in the test string in real time. Includes named group extraction, match count, a library of common presets, and flag toggles (g, i, m, s).

---

## How to Use

1. **Type a pattern** in the `/pattern/` input at the top
2. **Toggle flags** — `g` (global), `i` (case-insensitive), `m` (multiline), `s` (dotAll)
3. **Edit the test string** — paste any text to test against
4. **Click a preset** in the right panel to load a common pattern instantly

---

## Preset Patterns Included

| Preset | Pattern matches |
|--------|----------------|
| Email | Standard email addresses |
| URL | HTTP and HTTPS URLs |
| UUID | RFC 4122 UUIDs |
| Hex Color | CSS hex colors (#fff, #7c3aed) |
| ISO Date | YYYY-MM-DD date strings |
| IP Address | IPv4 addresses |
| Phone (US) | US phone numbers with country code |
| Markdown Link | `[text](url)` link syntax |

---

## Reading Results

- **Purple highlight** — a match in the test string
- **Brighter purple** — the first match
- **Match list** — shows each match text and its character index
- Named capture groups are shown in the match list as `groups: {name: value}`

---

## Common Flags

| Flag | Meaning |
|------|---------|
| `g` | Global — find all matches, not just the first |
| `i` | Case-insensitive match |
| `m` | Multiline — `^` and `$` match line boundaries |
| `s` | Dotall — `.` matches newlines |


---

## Bundled Files

### `regex-playground.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Regex Playground</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #0a0a14; color: #e2e8f0; font-family: system-ui, sans-serif; height: 100vh; display: flex; flex-direction: column; }
header { background: #1a1a2e; border-bottom: 1px solid #2d2d4e; padding: 11px 20px; flex-shrink: 0; }
h1 { font-size: 15px; color: #a78bfa; font-weight: 700; }
.layout { display: flex; flex: 1; overflow: hidden; }
.left { flex: 1; display: flex; flex-direction: column; padding: 18px; gap: 14px; overflow-y: auto; }
.right { width: 210px; background: #0d0d1c; border-left: 1px solid #1e1e3a; padding: 14px; overflow-y: auto; flex-shrink: 0; }
.label { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; margin-bottom: 6px; display: block; }
.pat-row { display: flex; align-items: center; background: #12121e; border: 1px solid #2d2d4e; border-radius: 8px; overflow: hidden; }
.sl { color: #4b5563; padding: 0 8px; font-size: 20px; font-family: monospace; }
#pat { flex: 1; background: transparent; border: none; outline: none; font-family: monospace; font-size: 16px; color: #c4b5fd; padding: 10px 0; }
.flags { display: flex; gap: 4px; padding: 8px; border-left: 1px solid #2d2d4e; }
.flag { padding: 4px 8px; border-radius: 4px; cursor: pointer; font-family: monospace; font-size: 12px; font-weight: 800; background: #1e1e3a; color: #4b5563; border: 1px solid transparent; user-select: none; transition: all 0.1s; }
.flag.on { background: #2d1b69; color: #c4b5fd; border-color: #6d28d9; }
.test-wrap { position: relative; }
#hl { position: absolute; inset: 0; padding: 11px 12px; font-family: monospace; font-size: 13px; line-height: 1.65; pointer-events: none; border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; color: transparent; overflow: hidden; }
mark { background: rgba(109,40,217,0.45); color: transparent; border-radius: 2px; }
mark.first { background: rgba(109,40,217,0.8); }
#tstr { width: 100%; min-height: 150px; background: #12121e; border: 1px solid #2d2d4e; border-radius: 8px; padding: 11px 12px; font-family: monospace; font-size: 13px; color: #e2e8f0; resize: vertical; outline: none; line-height: 1.65; }
#tstr:focus { border-color: #4c1d95; }
.status { display: flex; align-items: center; gap: 14px; min-height: 20px; }
.count { font-size: 13px; font-weight: 700; }
.found { color: #6ee7b7; }
.none  { color: #f87171; }
.err   { color: #fcd34d; font-size: 12px; }
.mlist { background: #12121e; border: 1px solid #1e1e3a; border-radius: 8px; padding: 10px 12px; font-family: monospace; font-size: 11px; max-height: 130px; overflow-y: auto; }
.mi { color: #a78bfa; padding: 3px 0; border-bottom: 1px solid #1a1a2e; }
.right-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; margin-bottom: 10px; }
.preset { padding: 7px 9px; border-radius: 6px; cursor: pointer; margin-bottom: 5px; border: 1px solid #1e1e3a; transition: background 0.1s; }
.preset:hover { background: #1a1a2e; }
.pname { font-size: 12px; font-weight: 600; color: #94a3b8; margin-bottom: 2px; }
.ppat  { font-family: monospace; font-size: 9px; color: #4b5563; word-break: break-all; }
</style>
</head>
<body>
<header><h1>&#10033; Regex Playground</h1></header>
<div class="layout">
<div class="left">
  <div>
    <span class="label">Pattern</span>
    <div class="pat-row">
      <span class="sl">/</span>
      <input id="pat" placeholder="enter a regex..." oninput="upd()">
      <span class="sl">/</span>
      <div class="flags">
        <span class="flag on" data-f="g" onclick="togFlag(this)">g</span>
        <span class="flag" data-f="i" onclick="togFlag(this)">i</span>
        <span class="flag" data-f="m" onclick="togFlag(this)">m</span>
        <span class="flag" data-f="s" onclick="togFlag(this)">s</span>
      </div>
    </div>
  </div>
  <div class="test-wrap">
    <span class="label">Test String</span>
    <div id="hl"></div>
    <textarea id="tstr" oninput="upd()" spellcheck="false">Contact us at hello@example.com or support@skillslap.com
Visit https://skillslap.com or https://dev.skillslap.com
User ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Color: #7c3aed or #fff or #a1b2c3
Date: 2026-02-20 | IP: 192.168.1.100
Phone: +1 (555) 123-4567</textarea>
  </div>
  <div class="status">
    <span id="cnt" class="count"></span>
    <span id="errmsg" class="err"></span>
  </div>
  <div>
    <span class="label">Matches</span>
    <div id="mlist" class="mlist"><span style="color:#2d2d4e">No pattern entered</span></div>
  </div>
</div>
<div class="right">
  <div class="right-lbl">Presets</div>
  <div id="presets"></div>
</div>
</div>
<script>
var P = [
  {n:'Email',   p:'[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}', f:'gi'},
  {n:'URL',     p:'https?:\\/\\/[\\w\\-]+(\\.[\\w\\-]+)+(\\/[^\\s]*)?', f:'gi'},
  {n:'UUID',    p:'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', f:'gi'},
  {n:'Hex Color',  p:'#[0-9a-fA-F]{6}\\b|#[0-9a-fA-F]{3}\\b', f:'g'},
  {n:'ISO Date',   p:'\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])', f:'g'},
  {n:'IP Address', p:'\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b', f:'g'},
  {n:'Phone (US)', p:'(?:\\+1\\s?)?\\(?\\d{3}\\)?[\\s.\\-]?\\d{3}[\\s.\\-]?\\d{4}', f:'g'},
  {n:'Markdown Link', p:'\\[([^\\]]+)\\]\\(([^)]+)\\)', f:'g'},
];

function esc(s){ return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
function flags(){ return Array.from(document.querySelectorAll('.flag.on')).map(function(f){return f.dataset.f;}).join(''); }
function setFlags(f){ document.querySelectorAll('.flag').forEach(function(el){ el.classList.toggle('on', f.indexOf(el.dataset.f)>=0); }); }
function togFlag(el){ el.classList.toggle('on'); upd(); }

function renderPresets(){
  document.getElementById('presets').innerHTML = P.map(function(p,i){
    return '<div class="preset" onclick="applyP('+i+')">'
      +'<div class="pname">'+p.n+'</div>'
      +'<div class="ppat">/'+p.p.slice(0,25)+(p.p.length>25?'...':'')+'/'+p.f+'</div></div>';
  }).join('');
}

function applyP(i){
  document.getElementById('pat').value = P[i].p;
  setFlags(P[i].f);
  upd();
}

function upd(){
  var patStr = document.getElementById('pat').value;
  var testStr = document.getElementById('tstr').value;
  var fl = flags();
  var cntEl = document.getElementById('cnt');
  var errEl = document.getElementById('errmsg');
  var hl = document.getElementById('hl');
  var ml = document.getElementById('mlist');

  if(!patStr){
    hl.innerHTML = esc(testStr);
    cntEl.textContent=''; errEl.textContent='';
    ml.innerHTML = '<span style="color:#2d2d4e">No pattern entered</span>';
    return;
  }

  var re;
  try { re = new RegExp(patStr, fl); errEl.textContent=''; }
  catch(e){ errEl.textContent = e.message; cntEl.textContent=''; hl.innerHTML=esc(testStr); ml.innerHTML=''; return; }

  var matches = [];
  var gfl = fl.indexOf('g')>=0 ? fl : fl+'g';
  var gr = new RegExp(patStr, gfl);
  var m;
  while((m = gr.exec(testStr)) !== null){
    matches.push({idx:m.index, txt:m[0], grps:m.groups});
    if(!fl.indexOf('g')>=0) break;
  }

  var res='', last=0;
  matches.forEach(function(m,i){
    res += esc(testStr.slice(last, m.idx));
    res += '<mark class="'+(i===0?'first':'')+'">' + esc(m.txt) + '</mark>';
    last = m.idx + m.txt.length;
  });
  res += esc(testStr.slice(last));
  hl.innerHTML = res;

  cntEl.className = 'count '+(matches.length>0?'found':'none');
  cntEl.textContent = matches.length + (matches.length===1?' match':' matches');

  if(matches.length===0){
    ml.innerHTML='<span style="color:#2d2d4e">No matches found</span>';
  } else {
    ml.innerHTML = matches.slice(0,20).map(function(m,i){
      return '<div class="mi">['+i+'] "'+esc(m.txt)+'" at '+m.idx+(m.grps?' groups:'+JSON.stringify(m.grps):'')+' </div>';
    }).join('') + (matches.length>20?'<div style="color:#2d2d4e">...and '+(matches.length-20)+' more</div>':'');
  }
}

document.getElementById('tstr').addEventListener('scroll', function(){
  document.getElementById('hl').scrollTop = this.scrollTop;
});

renderPresets();
applyP(0);
</script>
</body>
</html>
```
