Emoji Picker

Interface for inserting emoji.

😀 🐨 🍉
😀😁😂😍😎🙂
🐶🐱🐨🦊🐸🐧
🍎🍉🍕🍩🥑🍓

html

<div class="emoji" data-category="smileys" style="--accent:#E8A020;border-radius:12px;">
  <div class="emoji__search">
    <svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><circle cx="8.5" cy="8.5" r="6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M13 13l4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
    <input type="text" placeholder="Search emoji" readonly>
  </div>
  <div class="emoji__tabs" role="tablist" aria-label="Emoji categories">
    <span class="emoji__tab" data-tab="smileys">&#128512;</span>
    <span class="emoji__tab" data-tab="animals">&#128040;</span>
    <span class="emoji__tab" data-tab="food">&#127817;</span>
  </div>
  <div class="emoji__grid" style="grid-template-columns:repeat(6, 1fr);">
    <div class="emoji__group emoji__group--smileys"><span class="emoji__item">😀</span><span class="emoji__item">😁</span><span class="emoji__item">😂</span><span class="emoji__item">😍</span><span class="emoji__item">😎</span><span class="emoji__item">🙂</span></div>
    <div class="emoji__group emoji__group--animals"><span class="emoji__item">🐶</span><span class="emoji__item">🐱</span><span class="emoji__item">🐨</span><span class="emoji__item">🦊</span><span class="emoji__item">🐸</span><span class="emoji__item">🐧</span></div>
    <div class="emoji__group emoji__group--food"><span class="emoji__item">🍎</span><span class="emoji__item">🍉</span><span class="emoji__item">🍕</span><span class="emoji__item">🍩</span><span class="emoji__item">🥑</span><span class="emoji__item">🍓</span></div>
  </div>
</div>
<style>
.emoji { font: 14px system-ui, sans-serif; background: #FAF7F2; color: #241430; border: 1.5px solid #24143022; padding: 12px; max-width: 260px; }
.emoji__search { display: flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1.5px solid #24143033; border-radius: 8px; margin-bottom: 10px; color: #24143099; }
.emoji__search input { border: none; outline: none; background: none; font: inherit; color: #241430; flex: 1; }
.emoji__tabs { display: flex; gap: 4px; margin-bottom: 10px; }
.emoji__tab { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; font-size: 15px; opacity: .45; }
.emoji[data-category="smileys"] .emoji__tab[data-tab="smileys"],
.emoji[data-category="animals"] .emoji__tab[data-tab="animals"],
.emoji[data-category="food"] .emoji__tab[data-tab="food"] { opacity: 1; background: color-mix(in srgb, var(--accent) 30%, #FAF7F2); }
.emoji__grid { display: grid; gap: 6px; font-size: 20px; }
.emoji__group { display: none; grid-column: 1 / -1; grid-template-columns: inherit; gap: 6px; }
.emoji[data-category="smileys"] .emoji__group--smileys,
.emoji[data-category="animals"] .emoji__group--animals,
.emoji[data-category="food"] .emoji__group--food { display: grid; }
.emoji__item { display: flex; align-items: center; justify-content: center; aspect-ratio: 1; border-radius: 6px; }
.emoji__item:hover { background: color-mix(in srgb, var(--accent) 20%, #FAF7F2); }
</style>

tailwind

<div data-category="smileys" style="--accent:#E8A020;border-radius:12px;" class="emoji-tw font-sans text-sm bg-[#FAF7F2] text-[#241430] border-[1.5px] border-[#24143022] p-3 max-w-[260px]">
  <div class="flex items-center gap-1.5 px-2.5 py-1.5 border-[1.5px] border-[#24143033] rounded-lg mb-2.5 text-[#241430]/60">
    <svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><circle cx="8.5" cy="8.5" r="6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M13 13l4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
    <input type="text" placeholder="Search emoji" readonly class="border-0 outline-none bg-transparent flex-1 text-[#241430]">
  </div>
  <div role="tablist" aria-label="Emoji categories" class="flex gap-1 mb-2.5">
    <span class="emoji-tw__tab" data-tab="smileys">&#128512;</span>
    <span class="emoji-tw__tab" data-tab="animals">&#128040;</span>
    <span class="emoji-tw__tab" data-tab="food">&#127817;</span>
  </div>
  <div class="grid gap-1.5 text-xl" style="grid-template-columns:repeat(6, 1fr);">
    <div class="emoji-tw__group emoji-tw__group--smileys"><span class="emoji-tw__item">😀</span><span class="emoji-tw__item">😁</span><span class="emoji-tw__item">😂</span><span class="emoji-tw__item">😍</span><span class="emoji-tw__item">😎</span><span class="emoji-tw__item">🙂</span></div>
    <div class="emoji-tw__group emoji-tw__group--animals"><span class="emoji-tw__item">🐶</span><span class="emoji-tw__item">🐱</span><span class="emoji-tw__item">🐨</span><span class="emoji-tw__item">🦊</span><span class="emoji-tw__item">🐸</span><span class="emoji-tw__item">🐧</span></div>
    <div class="emoji-tw__group emoji-tw__group--food"><span class="emoji-tw__item">🍎</span><span class="emoji-tw__item">🍉</span><span class="emoji-tw__item">🍕</span><span class="emoji-tw__item">🍩</span><span class="emoji-tw__item">🥑</span><span class="emoji-tw__item">🍓</span></div>
  </div>
</div>
<style>
.emoji-tw__tab { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; opacity: .45; }
.emoji-tw[data-category="smileys"] .emoji-tw__tab[data-tab="smileys"],
.emoji-tw[data-category="animals"] .emoji-tw__tab[data-tab="animals"],
.emoji-tw[data-category="food"] .emoji-tw__tab[data-tab="food"] { opacity: 1; background: color-mix(in srgb, var(--accent) 30%, #FAF7F2); }
.emoji-tw__group { display: none; grid-column: 1 / -1; grid-template-columns: inherit; gap: 6px; }
.emoji-tw[data-category="smileys"] .emoji-tw__group--smileys,
.emoji-tw[data-category="animals"] .emoji-tw__group--animals,
.emoji-tw[data-category="food"] .emoji-tw__group--food { display: grid; }
.emoji-tw__item { display: flex; align-items: center; justify-content: center; aspect-ratio: 1; border-radius: 6px; }
.emoji-tw__item:hover { background: color-mix(in srgb, var(--accent) 20%, #FAF7F2); }
</style>

react

export function EmojiPicker({
  searchPlaceholder = "Search emoji",
  category = "smileys",
  accent = "#E8A020",
  columns = 6,
  radius = 12,
}) {
  const groups = {
    smileys: ["\uD83D\uDE00", "\uD83D\uDE01", "\uD83D\uDE02", "\uD83D\uDE0D", "\uD83D\uDE0E", "\uD83D\uDE42"],
    animals: ["\uD83D\uDC36", "\uD83D\uDC31", "\uD83D\uDC28", "\uD83E\uDD8A", "\uD83D\uDC38", "\uD83D\uDC27"],
    food: ["\uD83C\uDF4E", "\uD83C\uDF49", "\uD83C\uDF55", "\uD83C\uDF69", "\uD83E\uDD51", "\uD83C\uDF53"],
  };
  const tabs = [
    { key: "smileys", glyph: "\uD83D\uDE00" },
    { key: "animals", glyph: "\uD83D\uDC28" },
    { key: "food", glyph: "\uD83C\uDF49" },
  ];
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", fontSize: 14, background: "#FAF7F2", color: "#241430",
      border: "1.5px solid #24143022", padding: 12, maxWidth: 260, borderRadius: radius }}>
      <div style={{ display: "flex", alignItems: "center", gap: 6, padding: "6px 10px", border: "1.5px solid #24143033",
        borderRadius: 8, marginBottom: 10, color: "#24143099" }}>
        <svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><circle cx="8.5" cy="8.5" r="6" fill="none" stroke="currentColor" strokeWidth="1.6" /><path d="M13 13l4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" /></svg>
        <input type="text" placeholder={searchPlaceholder} readOnly style={{ border: "none", outline: "none", background: "none", font: "inherit", color: "#241430", flex: 1 }} />
      </div>
      <div role="tablist" aria-label="Emoji categories" style={{ display: "flex", gap: 4, marginBottom: 10 }}>
        {tabs.map((t) => (
          <span key={t.key} style={{ width: 28, height: 28, display: "inline-flex", alignItems: "center", justifyContent: "center",
            borderRadius: 8, opacity: t.key === category ? 1 : 0.45,
            background: t.key === category ? `${accent}4d` : "transparent" }}>{t.glyph}</span>
        ))}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: 6, fontSize: 20 }}>
        {(groups[category] ?? groups.smileys).map((e, i) => (
          <span key={i} style={{ display: "flex", alignItems: "center", justifyContent: "center", aspectRatio: "1" }}>{e}</span>
        ))}
      </div>
    </div>
  );
}