Skip to content

Emoji-only mirrored textarea

can-mirror shares the textarea’s current value. A normal input listener filters local input before the mirrored value reaches other browsers.

Live exampleRoom connecting…
Remix
Test it with another person
  1. Keep this page open in your normal window.
  2. Copy the private-window link, then paste it into a private or incognito window.
  3. Interact in either window and watch the other one update.

Copy the code

The live playground and this source use the same Vanilla HTML recipe.

Save this as index.html, or open it in the playground to test and change it.

Remix

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Emoji-only mirrored textarea</title>
  <style>
    :root {
      color: #1c1c1c;
      background: #f4efe5;
      font-family: ui-sans-serif, system-ui, sans-serif;
    }
    * { box-sizing: border-box; }
    body { display: grid; min-height: 100vh; margin: 0; padding: 1rem; place-items: center; }
    main { width: min(34rem, 100%); }
    h1 { margin: 0 0 0.35rem; font-size: clamp(2rem, 8vw, 3.5rem); line-height: 1; }
    .intro { margin: 0 0 1.25rem; line-height: 1.5; }
    textarea {
      width: 100%;
      min-height: 8rem;
      resize: vertical;
      padding: 0.85rem 0.95rem;
      border: 1.5px solid #1c1c1c;
      border-radius: 6px;
      background: #f4efe5;
      box-shadow: 2px 2px 0 #1c1c1c;
      color: #1c1c1c;
      font: 1.75rem/1.35 ui-sans-serif, system-ui, sans-serif;
    }
    textarea:focus { outline: 3px solid #274b9e; outline-offset: 3px; }
    .hint {
      margin: 0.75rem 0 0;
      color: #6a6761;
      font: 0.74rem/1.5 ui-monospace, monospace;
      text-align: center;
    }
  </style>
</head>
<body>
  <main>
    <textarea
      id="emoji-pad"
      rows="4"
      placeholder="emojis only..."
      aria-label="Emoji-only shared textarea"
      can-mirror
    ></textarea>
    <p class="hint">Type anything. Only emojis stick, and the filtered value mirrors to everyone.</p>
  </main>

  <script type="module">
    import { playhtml } from "playhtml";

    const emojiOnly = /\p{Extended_Pictographic}/gu;
    const emojiPad = document.getElementById("emoji-pad");

    emojiPad.addEventListener("input", () => {
      const matches = emojiPad.value.match(emojiOnly);
      emojiPad.value = matches ? matches.join("") : "";
    });

    await playhtml.init({ developmentMode: true });
  </script>
</body>
</html>

The filter uses the browser’s Unicode emoji property:

const emojiOnly = /\p{Extended_Pictographic}/gu;

emojiPad.addEventListener("input", () => {
  const matches = emojiPad.value.match(emojiOnly);
  emojiPad.value = matches ? matches.join("") : "";
});

The application code changes a normal textarea. can-mirror observes the resulting form state and shares it.

Type letters and emoji in one window. Only the emoji should remain, and the other window should show the same filtered value.

See can-mirror for its DOM boundary and other supported form elements.