User Picker

Selects users.

html

<div class="userpicker userpicker--sel-priya userpicker--avatars" style="--accent:#BFD9F2;">
  <label id="up-label" for="up-input" class="userpicker__label">Assignee</label>
  <input id="up-input" type="text" role="combobox" aria-expanded="true" aria-controls="up-list" aria-activedescendant="up-opt-priya" aria-autocomplete="list" class="userpicker__input" placeholder="Search people…">
  
  <ul role="listbox" id="up-list" aria-labelledby="up-label" class="userpicker__list">
    <li role="option" id="up-opt-priya" data-key="priya" aria-selected="true" class="userpicker__option"><svg class="userpicker__avatar" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#D9C8F0"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">PS</text></svg>Priya Shah</li>
    <li role="option" id="up-opt-sam" data-key="sam" aria-selected="false" class="userpicker__option"><svg class="userpicker__avatar" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#A8E6C1"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">SO</text></svg>Sam Ortiz</li>
    <li role="option" id="up-opt-lena" data-key="lena" aria-selected="false" class="userpicker__option"><svg class="userpicker__avatar" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#F5C2E0"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">LF</text></svg>Lena Fischer</li>
  </ul>
  
</div>
<style>
.userpicker { display: block; font: 14px system-ui, sans-serif; color: #241430; max-width: 260px; }
.userpicker__label { display: block; margin-bottom: 6px; font-weight: 500; }
.userpicker__input { width: 100%; box-sizing: border-box; padding: 10px 12px; font: inherit; color: #241430; background: #FAF7F2; border: 1.5px solid #24143040; border-radius: 8px; }
.userpicker__input:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent); }
.userpicker__list { list-style: none; margin: 6px 0 0; padding: 4px; border: 1.5px solid #24143040; border-radius: 8px; background: #fff; }
.userpicker__option { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; cursor: pointer; }
.userpicker__option:hover { background: #24143010; }
.userpicker__avatar { display: none; flex: none; border-radius: 50%; }
.userpicker--avatars .userpicker__avatar { display: block; }
.userpicker--sel-priya [data-key="priya"],
.userpicker--sel-sam [data-key="sam"],
.userpicker--sel-lena [data-key="lena"] { background: #24143010; font-weight: 600; }
</style>

tailwind

<div class="userpicker-tw--sel-priya userpicker-tw--avatars block font-sans text-sm text-[#241430] max-w-[260px]" style="--accent:#BFD9F2;">
  <label id="up-label-tw" for="up-input-tw" class="block mb-1.5 font-medium">Assignee</label>
  <input id="up-input-tw" type="text" role="combobox" aria-expanded="true" aria-controls="up-list-tw" aria-activedescendant="up-opt-tw-priya" aria-autocomplete="list" placeholder="Search people…"
    class="w-full box-border px-3 py-2.5 bg-[#FAF7F2] border-[1.5px] border-[#24143040] rounded-lg focus-visible:outline-none focus-visible:border-[color:var(--accent)]">
  
  <ul role="listbox" id="up-list-tw" aria-labelledby="up-label-tw" class="list-none mt-1.5 p-1 border-[1.5px] border-[#24143040] rounded-lg bg-white">
    <li role="option" id="up-opt-tw-priya" data-key="priya" aria-selected="true" class="up-opt-tw flex items-center gap-2 px-2.5 py-1.5 rounded-md cursor-pointer hover:bg-[#24143010]"><svg class="up-avatar-tw" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#D9C8F0"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">PS</text></svg>Priya Shah</li>
    <li role="option" id="up-opt-tw-sam" data-key="sam" aria-selected="false" class="up-opt-tw flex items-center gap-2 px-2.5 py-1.5 rounded-md cursor-pointer hover:bg-[#24143010]"><svg class="up-avatar-tw" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#A8E6C1"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">SO</text></svg>Sam Ortiz</li>
    <li role="option" id="up-opt-tw-lena" data-key="lena" aria-selected="false" class="up-opt-tw flex items-center gap-2 px-2.5 py-1.5 rounded-md cursor-pointer hover:bg-[#24143010]"><svg class="up-avatar-tw" width="22" height="22" viewBox="0 0 22 22" aria-hidden="true"><circle cx="11" cy="11" r="11" fill="#F5C2E0"/><text x="11" y="15" font-size="9" font-family="system-ui, sans-serif" text-anchor="middle" fill="#241430">LF</text></svg>Lena Fischer</li>
  </ul>
  
</div>
<style>
.up-avatar-tw { display: none; flex: none; border-radius: 9999px; }
.userpicker-tw--avatars .up-avatar-tw { display: block; }
.userpicker-tw--sel-priya [data-key="priya"],
.userpicker-tw--sel-sam [data-key="sam"],
.userpicker-tw--sel-lena [data-key="lena"] { background: #24143010; font-weight: 600; }
</style>

react

export function UserPicker({
  label = "Assignee",
  selectedUser = "priya",
  open = true,
  showAvatar = true,
  accent = "#BFD9F2",
}) {
  const people = [
    { key: "priya", name: "Priya Shah", initials: "PS", colour: "#D9C8F0" },
    { key: "sam", name: "Sam Ortiz", initials: "SO", colour: "#A8E6C1" },
    { key: "lena", name: "Lena Fischer", initials: "LF", colour: "#F5C2E0" },
  ];
  return (
    <div style={{ display: "block", fontFamily: "system-ui, sans-serif", fontSize: 14, color: "#241430", maxWidth: 260 }}>
      <label id="up-label-r" htmlFor="up-input-r" style={{ display: "block", marginBottom: 6, fontWeight: 500 }}>{label}</label>
      <input id="up-input-r" type="text" role="combobox" aria-expanded={open} aria-controls="up-list-r" aria-activedescendant={`up-opt-r-${selectedUser}`} aria-autocomplete="list" placeholder="Search people…" style={{
        width: "100%", boxSizing: "border-box", padding: "10px 12px", font: "inherit", color: "#241430",
        background: "#FAF7F2", border: "1.5px solid #24143040", borderRadius: 8,
      }} />
      {open && (
        <ul role="listbox" id="up-list-r" aria-labelledby="up-label-r" style={{ listStyle: "none", margin: "6px 0 0", padding: 4, border: "1.5px solid #24143040", borderRadius: 8, background: "#fff" }}>
          {people.map((person) => (
            <li key={person.key} id={`up-opt-r-${person.key}`} role="option" aria-selected={person.key === selectedUser} style={{
              display: "flex", alignItems: "center", gap: 8, padding: "6px 10px", borderRadius: 6, cursor: "pointer",
              background: person.key === selectedUser ? "#24143010" : "transparent",
              fontWeight: person.key === selectedUser ? 600 : 400,
            }}>
              {showAvatar && (
                <svg width="22" height="22" viewBox="0 0 22 22" aria-hidden="true" style={{ flex: "none", borderRadius: "50%" }}>
                  <circle cx="11" cy="11" r="11" fill={person.colour} />
                  <text x="11" y="15" fontSize="9" fontFamily="system-ui, sans-serif" textAnchor="middle" fill="#241430">{person.initials}</text>
                </svg>
              )}
              {person.name}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}