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: 1.5rem; 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: 11rem;
      resize: vertical;
      padding: 1rem;
      border: 2px solid #1c1c1c;
      background: #fffdf8;
      box-shadow: 5px 5px 0 #1c1c1c;
      color: #1c1c1c;
      font: 2rem/1.4 system-ui, sans-serif;
    }
    textarea:focus { outline: 3px solid #274b9e; outline-offset: 3px; }
    .hint { margin: 0.85rem 0 0; color: #5a5650; font-size: 0.9rem; }
  </style>
</head>
<body>
  <main>
    <h1>Emoji pad</h1>
    <p class="intro">Type anything. Only emoji remain, and the value updates for everyone.</p>
    <textarea
      id="emoji-pad"
      rows="4"
      placeholder="emojis only..."
      aria-label="Emoji-only shared textarea"
      can-mirror
    ></textarea>
    <p class="hint">Try the same room in another browser window.</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.