Multi-select

Select multiple values.

Notification channels

2 of 5 selected · choose up to 3

html

<fieldset class="mselect mselect--list" style="--accent:#F5C2E0;">
  <legend class="mselect__legend">Notification channels</legend>
  <p role="status" class="mselect__status">2 of 5 selected &middot; choose up to 3</p>
  <label class="mselect__option"><input type="checkbox" name="channel" value="email" checked> Email</label>
  <label class="mselect__option"><input type="checkbox" name="channel" value="sms" checked> SMS</label>
  <label class="mselect__option"><input type="checkbox" name="channel" value="push"> Push</label>
  <label class="mselect__option"><input type="checkbox" name="channel" value="slack"> Slack</label>
  <label class="mselect__option"><input type="checkbox" name="channel" value="webhook"> Webhook</label>
</fieldset>
<style>
.mselect { font: 14px system-ui, sans-serif; color: #241430; max-width: 280px; border: 1.5px solid #24143040; border-radius: 8px; padding: 12px; }
.mselect__legend { font-weight: 600; padding: 0 4px; }
.mselect__status { margin: 2px 0 10px; font-size: 12.5px; color: #24143099; }
.mselect__option { display: flex; align-items: center; gap: 8px; padding: 6px 4px; cursor: pointer; border-radius: 6px; }
.mselect__option:hover { background: #24143008; }
.mselect--grid { display: grid; grid-template-columns: 1fr 1fr; }
.mselect--grid .mselect__status { grid-column: 1 / -1; }
.mselect__option input { width: 16px; height: 16px; accent-color: var(--accent); }
</style>

tailwind

<fieldset class="mselect-tw--list font-sans text-sm text-[#241430] max-w-[280px] border-[1.5px] border-[#24143040] rounded-lg p-3">
  <legend class="font-semibold px-1">Notification channels</legend>
  <p role="status" class="mselect-status-tw mt-0.5 mb-2.5 text-xs text-[#24143099]">2 of 5 selected &middot; choose up to 3</p>
  <label class="flex items-center gap-2 px-1 py-1.5 rounded-md cursor-pointer hover:bg-[#24143008]"><input type="checkbox" name="channel" value="email" class="w-4 h-4" style="accent-color:#F5C2E0;" checked> Email</label>
  <label class="flex items-center gap-2 px-1 py-1.5 rounded-md cursor-pointer hover:bg-[#24143008]"><input type="checkbox" name="channel" value="sms" class="w-4 h-4" style="accent-color:#F5C2E0;" checked> SMS</label>
  <label class="flex items-center gap-2 px-1 py-1.5 rounded-md cursor-pointer hover:bg-[#24143008]"><input type="checkbox" name="channel" value="push" class="w-4 h-4" style="accent-color:#F5C2E0;"> Push</label>
  <label class="flex items-center gap-2 px-1 py-1.5 rounded-md cursor-pointer hover:bg-[#24143008]"><input type="checkbox" name="channel" value="slack" class="w-4 h-4" style="accent-color:#F5C2E0;"> Slack</label>
  <label class="flex items-center gap-2 px-1 py-1.5 rounded-md cursor-pointer hover:bg-[#24143008]"><input type="checkbox" name="channel" value="webhook" class="w-4 h-4" style="accent-color:#F5C2E0;"> Webhook</label>
</fieldset>
<style>
.mselect-tw--grid { display: grid; grid-template-columns: 1fr 1fr; }
.mselect-tw--grid .mselect-status-tw { grid-column: 1 / -1; }
</style>

react

export function MultiSelect({
  label = "Notification channels",
  selectedCount = 2,
  maxSelectable = 3,
  layout = "list",
  accent = "#F5C2E0",
}) {
  const options = [
    { value: "email", text: "Email", checked: true },
    { value: "sms", text: "SMS", checked: true },
    { value: "push", text: "Push", checked: false },
    { value: "slack", text: "Slack", checked: false },
    { value: "webhook", text: "Webhook", checked: false },
  ];
  return (
    <fieldset style={{
      font: "14px system-ui, sans-serif", color: "#241430", maxWidth: 280,
      border: "1.5px solid #24143040", borderRadius: 8, padding: 12,
      display: layout === "grid" ? "grid" : "block",
      gridTemplateColumns: layout === "grid" ? "1fr 1fr" : undefined,
    }}>
      <legend style={{ fontWeight: 600, padding: "0 4px" }}>{label}</legend>
      <p role="status" style={{
        margin: "2px 0 10px", fontSize: 12.5, color: "#24143099",
        gridColumn: layout === "grid" ? "1 / -1" : undefined,
      }}>{selectedCount} of 5 selected &middot; choose up to {maxSelectable}</p>
      {options.map((opt) => (
        <label key={opt.value} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 4px", cursor: "pointer" }}>
          <input type="checkbox" defaultChecked={opt.checked} style={{ width: 16, height: 16, accentColor: accent }} /> {opt.text}
        </label>
      ))}
    </fieldset>
  );
}