Mention Picker

User selection when typing a mention.

html

<div class="mp" style="--accent:#A8E6C1;" data-style="both">
  <label class="mp__label" for="mp-input">Mention someone</label>
  <input id="mp-input" type="text" class="mp__input" role="combobox" aria-expanded="true" aria-controls="mp-listbox" aria-autocomplete="list" value="@sam" autocomplete="off">
  
  <ul id="mp-listbox" class="mp__listbox" role="listbox" aria-label="Matching people">
    <li role="option" aria-selected="true" class="mp__option">
      <span class="mp__avatar" aria-hidden="true">SK</span>
      <span class="mp__name">Samira Khan</span>
      <span class="mp__handle">@samira</span>
    </li>
    <li role="option" aria-selected="false" class="mp__option">
      <span class="mp__avatar" aria-hidden="true">SC</span>
      <span class="mp__name">Sam Chen</span>
      <span class="mp__handle">@samc</span>
    </li>
    <li role="option" aria-selected="false" class="mp__option">
      <span class="mp__avatar" aria-hidden="true">SP</span>
      <span class="mp__name">Samuel Park</span>
      <span class="mp__handle">@spark</span>
    </li>
  </ul>
  
</div>
<style>
.mp { font: 13.5px/1.4 system-ui, sans-serif; color: #241430; background: #FAF7F2; max-width: 260px; width: 260px; padding: 14px; border-radius: 12px; box-sizing: border-box; }
.mp__label { display: block; font-size: 11px; font-weight: 700; color: #241430a0; margin-bottom: 5px; }
.mp__input { display: block; width: 100%; box-sizing: border-box; padding: 7px 10px; border: 1.5px solid var(--accent); border-radius: 8px; font: inherit; color: #241430; background: #fff; }
.mp__input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.mp__listbox { list-style: none; margin: 6px 0 0; padding: 4px; background: #fff; border-radius: 10px; box-shadow: 0 4px 14px rgba(36,20,48,.14); }
.mp__option { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; }
.mp__option[aria-selected="true"] { background: var(--accent); }
.mp__avatar { width: 22px; height: 22px; border-radius: 50%; background: #241430; color: #FAF7F2; font-size: 9px; font-weight: 700; display: grid; place-items: center; flex-shrink: 0; }
.mp__name { font-weight: 600; }
.mp__handle { font-size: 11px; color: #241430a0; }
.mp[data-style="name"] .mp__handle { display: none; }
.mp[data-style="handle"] .mp__name { display: none; }
</style>

tailwind

<div class="mp-tw font-sans text-[13.5px] text-[#241430] bg-[#FAF7F2] max-w-[260px] w-[260px] p-3.5 rounded-xl box-border" style="--accent:#A8E6C1" data-style="both">
  <label for="mpt-input" class="block text-[11px] font-bold text-[#241430a0] mb-1">Mention someone</label>
  <input id="mpt-input" type="text" role="combobox" aria-expanded="true" aria-controls="mpt-listbox" aria-autocomplete="list" value="@sam" autocomplete="off" class="block w-full box-border py-1.5 px-2.5 rounded-lg font-sans text-[#241430] bg-white" style="border:1.5px solid #A8E6C1">
  
  <ul id="mpt-listbox" role="listbox" aria-label="Matching people" class="mp-tw__listbox list-none mt-1.5 mb-0 p-1 bg-white rounded-[10px] shadow-lg">
    <li role="option" aria-selected="true" class="mp-tw__option flex items-center gap-2 py-1.5 px-2 rounded-md" style="background:#A8E6C1">
      <span aria-hidden="true" class="w-[22px] h-[22px] rounded-full bg-[#241430] text-[#FAF7F2] text-[9px] font-bold grid place-items-center flex-shrink-0">SK</span>
      <span class="mp-tw__name font-semibold">Samira Khan</span>
      <span class="mp-tw__handle text-[11px] text-[#241430a0]">@samira</span>
    </li>
    <li role="option" aria-selected="false" class="mp-tw__option flex items-center gap-2 py-1.5 px-2 rounded-md">
      <span aria-hidden="true" class="w-[22px] h-[22px] rounded-full bg-[#241430] text-[#FAF7F2] text-[9px] font-bold grid place-items-center flex-shrink-0">SC</span>
      <span class="mp-tw__name font-semibold">Sam Chen</span>
      <span class="mp-tw__handle text-[11px] text-[#241430a0]">@samc</span>
    </li>
    <li role="option" aria-selected="false" class="mp-tw__option flex items-center gap-2 py-1.5 px-2 rounded-md">
      <span aria-hidden="true" class="w-[22px] h-[22px] rounded-full bg-[#241430] text-[#FAF7F2] text-[9px] font-bold grid place-items-center flex-shrink-0">SP</span>
      <span class="mp-tw__name font-semibold">Samuel Park</span>
      <span class="mp-tw__handle text-[11px] text-[#241430a0]">@spark</span>
    </li>
  </ul>
  
</div>
<style>
.mp-tw[data-style="name"] .mp-tw__handle { display: none; }
.mp-tw[data-style="handle"] .mp-tw__name { display: none; }
</style>

react

export function MentionPicker({
  label = "Mention someone",
  query = "sam",
  accent = "#A8E6C1",
  expanded = true,
  displayStyle = "both",
}) {
  const people = [
    { initials: "SK", name: "Samira Khan", handle: "@samira", selected: true },
    { initials: "SC", name: "Sam Chen", handle: "@samc", selected: false },
    { initials: "SP", name: "Samuel Park", handle: "@spark", selected: false },
  ];
  const showName = displayStyle !== "handle";
  const showHandle = displayStyle !== "name";
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", fontSize: 13.5, color: "#241430", background: "#FAF7F2", maxWidth: 260, width: 260, padding: 14, borderRadius: 12, boxSizing: "border-box" }}>
      <label htmlFor="mpr-input" style={{ display: "block", fontSize: 11, fontWeight: 700, color: "#241430a0", marginBottom: 5 }}>{label}</label>
      <input id="mpr-input" type="text" role="combobox" aria-expanded={expanded} aria-controls="mpr-listbox" aria-autocomplete="list" defaultValue={`@${query}`} autoComplete="off" style={{ display: "block", width: "100%", boxSizing: "border-box", padding: "7px 10px", border: `1.5px solid ${accent}`, borderRadius: 8, font: "inherit", color: "#241430", background: "#fff" }} />
      {expanded && (
        <ul id="mpr-listbox" role="listbox" aria-label="Matching people" style={{ listStyle: "none", margin: "6px 0 0", padding: 4, background: "#fff", borderRadius: 10, boxShadow: "0 4px 14px rgba(36,20,48,.14)" }}>
          {people.map((p) => (
            <li key={p.handle} role="option" aria-selected={p.selected} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", borderRadius: 6, background: p.selected ? accent : "transparent" }}>
              <span aria-hidden="true" style={{ width: 22, height: 22, borderRadius: "50%", background: "#241430", color: "#FAF7F2", fontSize: 9, fontWeight: 700, display: "grid", placeItems: "center", flexShrink: 0 }}>{p.initials}</span>
              {showName && <span style={{ fontWeight: 600 }}>{p.name}</span>}
              {showHandle && <span style={{ fontSize: 11, color: "#241430a0" }}>{p.handle}</span>}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}