Open demo

CSS code

HTML
<div><span class="lbl">Default with a hint</span><div class="card">
  <div class="sel">
    <label class="sel-label" for="sel-country">Country of residence</label>
    <div class="sel-field">
      <select class="sel-input" id="sel-country" name="country" aria-describedby="sel-country-hint">
        <optgroup label="Baltics"><option value="EE">Estonia</option><option value="LV" selected>Latvia</option><option value="LT">Lithuania</option></optgroup>
        <optgroup label="Nordics"><option value="DK">Denmark</option><option value="FI">Finland</option><option value="NO">Norway</option><option value="SE">Sweden</option></optgroup>
        <optgroup label="Western Europe"><option value="BE">Belgium</option><option value="FR">France</option><option value="DE">Germany</option><option value="NL">Netherlands</option></optgroup>
      </select>
    </div>
    <p class="sel-hint" id="sel-country-hint">Used for tax and invoicing. You can change it later in Billing.</p>
  </div>
</div></div>

<div><span class="lbl">Three sizes</span><div class="card">
  <div class="sel-sizes">
    <div class="sel sel-sm"><label class="sel-label" for="sel-rows">Rows per page</label><div class="sel-field">
      <select class="sel-input" id="sel-rows" name="rows"><option>10</option><option selected>25</option><option>50</option><option>100</option></select></div></div>
    <div class="sel"><label class="sel-label" for="sel-sort">Sort by</label><div class="sel-field">
      <select class="sel-input" id="sel-sort" name="sort"><option>Newest first</option><option>Oldest first</option><option>Price, low to high</option><option>Price, high to low</option></select></div></div>
    <div class="sel sel-lg"><label class="sel-label" for="sel-plan">Plan</label><div class="sel-field">
      <select class="sel-input" id="sel-plan" name="plan"><option>Starter</option><option selected>Team</option><option>Business</option></select></div></div>
  </div>
</div></div>

<div><span class="lbl">Leading icon, pill shape</span><div class="card">
  <div class="sel-row">
    <div class="sel sel-pill"><label class="sel-label" for="sel-currency">Currency</label><div class="sel-field">
      <svg class="sel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="2.5" y="6" width="19" height="12" rx="2"/><circle cx="12" cy="12" r="2.6"/><path d="M6 9.5v5M18 9.5v5"/></svg>
      <select class="sel-input" id="sel-currency" name="currency"><option value="EUR" selected>EUR — Euro</option><option value="GBP">GBP — Pound sterling</option><option value="USD">USD — US dollar</option><option value="SEK">SEK — Swedish krona</option></select></div></div>
    <div class="sel sel-pill"><label class="sel-label" for="sel-lang">Language</label><div class="sel-field">
      <svg class="sel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9.5"/><path d="M2.5 12h19M12 2.5c2.6 2.8 3.8 6 3.8 9.5s-1.2 6.7-3.8 9.5c-2.6-2.8-3.8-6-3.8-9.5s1.2-6.7 3.8-9.5Z"/></svg>
      <select class="sel-input" id="sel-lang" name="language"><option value="en" selected>English</option><option value="de">Deutsch</option><option value="es">Español</option><option value="fr">Français</option><option value="lv">Latviešu</option></select></div></div>
  </div>
</div></div>

<div><span class="lbl">Valid, invalid and disabled</span><div class="card">
  <div class="sel-row">
    <div class="sel"><label class="sel-label" for="sel-ship">Delivery</label><div class="sel-field">
      <select class="sel-input is-valid" id="sel-ship" name="delivery" aria-describedby="sel-ship-msg"><option>Standard — 3 to 5 days</option><option selected>Express — next day</option><option>Collect from store</option></select></div>
      <p class="sel-msg ok" id="sel-ship-msg">Arrives Thursday, 2 October</p></div>
    <div class="sel"><label class="sel-label" for="sel-size">Frame size</label><div class="sel-field">
      <select class="sel-input" id="sel-size" name="size" required aria-invalid="true" aria-describedby="sel-size-msg"><option value="" selected>Choose a size</option><option>S — 160 to 170 cm</option><option>M — 170 to 180 cm</option><option>L — 180 to 190 cm</option></select></div>
      <p class="sel-msg err" id="sel-size-msg">Choose a frame size to continue.</p></div>
    <div class="sel"><label class="sel-label" for="sel-region">Data region</label><div class="sel-field">
      <select class="sel-input" id="sel-region" name="region" disabled aria-describedby="sel-region-hint"><option>EU — Frankfurt</option></select></div>
      <p class="sel-hint" id="sel-region-hint">Set when the workspace was created.</p></div>
  </div>
</div></div>

<div><span class="lbl">Native multiple select</span><div class="card">
  <div class="sel">
    <label class="sel-label" for="sel-topics">Newsletter topics</label>
    <select class="sel-input" id="sel-topics" name="topics" multiple size="6" aria-describedby="sel-topics-hint">
      <option value="product" selected>Product updates</option>
      <option value="engineering">Engineering blog</option>
      <option value="design" selected>Design notes</option>
      <option value="stories">Customer stories</option>
      <option value="events" selected>Events and webinars</option>
      <option value="jobs">Open roles</option>
    </select>
    <p class="sel-hint" id="sel-topics-hint">Hold Ctrl (or ⌘ on a Mac) to pick more than one.</p>
  </div>
</div></div>
CSS
/* Styled native selects: a real <select> with appearance:none and a chevron drawn as a background image.
   The browser keeps its own option list, keyboard handling, mobile pickers and form submission. */
.sel{--sel-accent:#4f46e5;--sel-ring:rgba(79,70,229,.28);--sel-line:#8a90a6;--sel-ink:#1e2233;--sel-muted:#596073;
  --sel-ok:#15803d;--sel-err:#c81e3a;--sel-h:44px;--sel-radius:10px;
  --sel-chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23596073' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  display:grid;gap:7px;min-width:0}
.sel-label{font-size:.9rem;font-weight:600;color:var(--sel-ink)}
.sel-hint{font-size:.82rem;color:var(--sel-muted)}
.sel-field{position:relative}
.sel-input{-webkit-appearance:none;appearance:none;display:block;width:100%;height:var(--sel-h);margin:0;padding:0 42px 0 14px;
  font:inherit;font-size:.95rem;color:var(--sel-ink);color-scheme:light;cursor:pointer;
  background:#fff var(--sel-chev) no-repeat right 14px center/16px;border:1px solid var(--sel-line);border-radius:var(--sel-radius);
  box-shadow:0 1px 2px rgba(20,24,40,.06);transition:border-color .15s,box-shadow .15s}
.sel-input:hover{border-color:#5f6579}
.sel-input:focus-visible{outline:none;border-color:var(--sel-accent);box-shadow:0 0 0 4px var(--sel-ring)}
/* sizes */
.sel-sm .sel-input{--sel-h:34px;padding-left:11px;padding-right:34px;font-size:.84rem;border-radius:8px;background-position:right 10px center;background-size:14px}
.sel-lg .sel-input{--sel-h:54px;padding-left:18px;padding-right:48px;font-size:1.05rem;border-radius:13px;background-position:right 18px center;background-size:18px}
.sel-sizes{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:16px;align-items:start}
/* leading icon and pill shape */
.sel-icon{position:absolute;left:15px;top:50%;width:18px;height:18px;margin-top:-9px;color:var(--sel-accent);pointer-events:none}
.sel-icon + .sel-input{padding-left:43px}
.sel-pill .sel-input{border-radius:999px;padding-right:44px;background-position:right 16px center}
.sel-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}
/* validation: a status icon beside the chevron and a message tied with aria-describedby */
.sel-input.is-valid,.sel-input[aria-invalid="true"]{padding-right:68px;background-image:var(--sel-chev),var(--sel-status);
  background-position:right 14px center,right 40px center;background-size:16px,16px}
.sel-input.is-valid{--sel-status:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2315803d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E");border-color:var(--sel-ok)}
.sel-input[aria-invalid="true"]{--sel-status:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23c81e3a' stroke-width='1.6'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M8 4.6v4' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.2' r='.6' fill='%23c81e3a'/%3E%3C/svg%3E");border-color:var(--sel-err)}
.sel-input.is-valid:focus-visible{box-shadow:0 0 0 4px rgba(21,128,61,.25)}
.sel-input[aria-invalid="true"]:focus-visible{box-shadow:0 0 0 4px rgba(200,30,58,.22)}
.sel-msg{font-size:.82rem;font-weight:500}
.sel-msg.ok{color:var(--sel-ok)}
.sel-msg.err{color:var(--sel-err)}
.sel-input:disabled{cursor:not-allowed;color:#6b7080;background-color:#f1f2f6;border-color:#cfd2dc;box-shadow:none}
/* a native multiple select, shown as a list */
.sel-input[multiple]{height:auto;padding:6px;background-image:none;overflow-y:auto;cursor:default}
.sel-input[multiple] option{padding:8px 10px;border-radius:7px;color:var(--sel-ink)}
.sel-input[multiple] option:checked{background:#e4e5ff linear-gradient(#e4e5ff,#e4e5ff);color:#312e81;font-weight:600}
@media (prefers-reduced-motion:reduce){.sel-input{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Default with a hint</span><div class="card demo-card"><div class="card-body">
  <div class="sel">
    <label class="form-label" for="sel-country">Country of residence</label>
    <select class="form-select" id="sel-country" name="country" aria-describedby="sel-country-hint">
      <optgroup label="Baltics"><option value="EE">Estonia</option><option value="LV" selected>Latvia</option><option value="LT">Lithuania</option></optgroup>
      <optgroup label="Nordics"><option value="DK">Denmark</option><option value="FI">Finland</option><option value="NO">Norway</option><option value="SE">Sweden</option></optgroup>
      <optgroup label="Western Europe"><option value="BE">Belgium</option><option value="FR">France</option><option value="DE">Germany</option><option value="NL">Netherlands</option></optgroup>
    </select>
    <p class="form-text" id="sel-country-hint">Used for tax and invoicing. You can change it later in Billing.</p>
  </div>
</div></div></div>

<div><span class="lbl">Three sizes</span><div class="card demo-card"><div class="card-body">
  <div class="row g-3">
    <div class="col-sm-4 sel"><label class="form-label" for="sel-rows">Rows per page</label>
      <select class="form-select form-select-sm" id="sel-rows" name="rows"><option>10</option><option selected>25</option><option>50</option><option>100</option></select></div>
    <div class="col-sm-4 sel"><label class="form-label" for="sel-sort">Sort by</label>
      <select class="form-select" id="sel-sort" name="sort"><option>Newest first</option><option>Oldest first</option><option>Price, low to high</option><option>Price, high to low</option></select></div>
    <div class="col-sm-4 sel"><label class="form-label" for="sel-plan">Plan</label>
      <select class="form-select form-select-lg" id="sel-plan" name="plan"><option>Starter</option><option selected>Team</option><option>Business</option></select></div>
  </div>
</div></div></div>

<div><span class="lbl">Leading icon, pill shape</span><div class="card demo-card"><div class="card-body">
  <div class="row g-3">
    <div class="col-sm-6 sel sel-pill"><label class="form-label" for="sel-currency">Currency</label><div class="sel-field">
      <svg class="sel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="2.5" y="6" width="19" height="12" rx="2"/><circle cx="12" cy="12" r="2.6"/><path d="M6 9.5v5M18 9.5v5"/></svg>
      <select class="form-select" id="sel-currency" name="currency"><option value="EUR" selected>EUR — Euro</option><option value="GBP">GBP — Pound sterling</option><option value="USD">USD — US dollar</option><option value="SEK">SEK — Swedish krona</option></select></div></div>
    <div class="col-sm-6 sel sel-pill"><label class="form-label" for="sel-lang">Language</label><div class="sel-field">
      <svg class="sel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9.5"/><path d="M2.5 12h19M12 2.5c2.6 2.8 3.8 6 3.8 9.5s-1.2 6.7-3.8 9.5c-2.6-2.8-3.8-6-3.8-9.5s1.2-6.7 3.8-9.5Z"/></svg>
      <select class="form-select" id="sel-lang" name="language"><option value="en" selected>English</option><option value="de">Deutsch</option><option value="es">Español</option><option value="fr">Français</option><option value="lv">Latviešu</option></select></div></div>
  </div>
</div></div></div>

<div><span class="lbl">Valid, invalid and disabled</span><div class="card demo-card"><div class="card-body">
  <div class="row g-3">
    <div class="col-sm-6 sel"><label class="form-label" for="sel-ship">Delivery</label>
      <select class="form-select is-valid" id="sel-ship" name="delivery" aria-describedby="sel-ship-msg"><option>Standard — 3 to 5 days</option><option selected>Express — next day</option><option>Collect from store</option></select>
      <p class="valid-feedback d-block" id="sel-ship-msg">Arrives Thursday, 2 October</p></div>
    <div class="col-sm-6 sel"><label class="form-label" for="sel-size">Frame size</label>
      <select class="form-select is-invalid" id="sel-size" name="size" required aria-invalid="true" aria-describedby="sel-size-msg"><option value="" selected>Choose a size</option><option>S — 160 to 170 cm</option><option>M — 170 to 180 cm</option><option>L — 180 to 190 cm</option></select>
      <p class="invalid-feedback d-block" id="sel-size-msg">Choose a frame size to continue.</p></div>
    <div class="col-sm-6 sel"><label class="form-label" for="sel-region">Data region</label>
      <select class="form-select" id="sel-region" name="region" disabled aria-describedby="sel-region-hint"><option>EU — Frankfurt</option></select>
      <p class="form-text" id="sel-region-hint">Set when the workspace was created.</p></div>
  </div>
</div></div></div>

<div><span class="lbl">Native multiple select</span><div class="card demo-card"><div class="card-body">
  <div class="sel">
    <label class="form-label" for="sel-topics">Newsletter topics</label>
    <select class="form-select" id="sel-topics" name="topics" multiple size="6" aria-describedby="sel-topics-hint">
      <option value="product" selected>Product updates</option>
      <option value="engineering">Engineering blog</option>
      <option value="design" selected>Design notes</option>
      <option value="stories">Customer stories</option>
      <option value="events" selected>Events and webinars</option>
      <option value="jobs">Open roles</option>
    </select>
    <p class="form-text" id="sel-topics-hint">Hold Ctrl (or ⌘ on a Mac) to pick more than one.</p>
  </div>
</div></div></div>
CSS
/* Styled native selects on Bootstrap's .form-select. The chevron and the valid / invalid icons are swapped
   through --bs-form-select-bg-img and --bs-form-select-bg-icon; the rest is size, colour and focus ring. */
.sel{--sel-accent:#4f46e5;--sel-ring:rgba(79,70,229,.28);--sel-line:#8a90a6;--sel-ink:#1e2233;--sel-muted:#596073;--sel-h:44px;
  --sel-chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23596073' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  --bs-form-valid-color:#15803d;--bs-form-valid-border-color:#15803d;--bs-form-invalid-color:#c81e3a;--bs-form-invalid-border-color:#c81e3a;
  display:grid;gap:7px;min-width:0}
.sel .form-label{margin:0;font-size:.9rem;font-weight:600;color:var(--sel-ink)}
.sel .form-text{margin:0;font-size:.82rem;color:var(--sel-muted)}
.sel .valid-feedback,.sel .invalid-feedback{margin:0;font-size:.82rem;font-weight:500}
.sel .form-select{--bs-form-select-bg-img:var(--sel-chev);height:var(--sel-h);padding:0 42px 0 14px;font-size:.95rem;line-height:1.45;color:var(--sel-ink);
  color-scheme:light;cursor:pointer;border-color:var(--sel-line);border-radius:10px;background-position:right 14px center;background-size:16px;
  box-shadow:0 1px 2px rgba(20,24,40,.06)}
.sel .form-select:hover{border-color:#5f6579}
.sel .form-select:focus{border-color:var(--sel-accent);box-shadow:0 0 0 4px var(--sel-ring)}
.sel .form-select-sm{--sel-h:34px;padding-left:11px;padding-right:34px;font-size:.84rem;border-radius:8px;background-position:right 10px center;background-size:14px}
.sel .form-select-lg{--sel-h:54px;padding-left:18px;padding-right:48px;font-size:1.05rem;border-radius:13px;background-position:right 18px center;background-size:18px}
.sel-field{position:relative}
.sel-icon{position:absolute;left:15px;top:50%;width:18px;height:18px;margin-top:-9px;color:var(--sel-accent);pointer-events:none;z-index:1}
.sel-icon + .form-select{padding-left:43px}
.sel-pill .form-select{border-radius:999px;padding-right:44px;background-position:right 16px center}
.sel .form-select.is-valid,.sel .form-select.is-invalid{padding-right:68px;background-position:right 14px center,right 40px center;background-size:16px,16px}
.sel .form-select.is-valid{--bs-form-select-bg-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2315803d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E")}
.sel .form-select.is-invalid{--bs-form-select-bg-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23c81e3a' stroke-width='1.6'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M8 4.6v4' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.2' r='.6' fill='%23c81e3a'/%3E%3C/svg%3E")}
.sel .form-select.is-valid{border-color:var(--bs-form-valid-border-color)}
.sel .form-select.is-invalid{border-color:var(--bs-form-invalid-border-color)}
.sel .form-select.is-valid:focus{box-shadow:0 0 0 4px rgba(21,128,61,.25)}
.sel .form-select.is-invalid:focus{box-shadow:0 0 0 4px rgba(200,30,58,.22)}
.sel .form-select:disabled{cursor:not-allowed;color:#6b7080;background-color:#f1f2f6;border-color:#cfd2dc;box-shadow:none}
.sel .form-select[multiple]{height:auto;padding:6px;cursor:default}
.sel .form-select[multiple] option{padding:8px 10px;border-radius:7px;color:var(--sel-ink)}
.sel .form-select[multiple] option:checked{background:#e4e5ff linear-gradient(#e4e5ff,#e4e5ff);color:#312e81;font-weight:600}
@media (prefers-reduced-motion:reduce){.sel .form-select{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#596073] uppercase">Default with a hint</span><div class="rounded-2xl border border-[#e3e5ee] bg-white px-6 pt-[22px] pb-6 shadow-[0_1px_2px_rgba(20,24,40,.04)]">
  <div class="grid min-w-0 gap-[7px]">
    <label class="text-[.9rem] font-semibold" for="sel-country">Country of residence</label>
    <select class="sel-chevron block h-11 w-full cursor-pointer appearance-none rounded-[10px] border border-sel-line bg-white pr-[42px] pl-3.5 text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-country" name="country" aria-describedby="sel-country-hint">
      <optgroup label="Baltics"><option value="EE">Estonia</option><option value="LV" selected>Latvia</option><option value="LT">Lithuania</option></optgroup>
      <optgroup label="Nordics"><option value="DK">Denmark</option><option value="FI">Finland</option><option value="NO">Norway</option><option value="SE">Sweden</option></optgroup>
      <optgroup label="Western Europe"><option value="BE">Belgium</option><option value="FR">France</option><option value="DE">Germany</option><option value="NL">Netherlands</option></optgroup>
    </select>
    <p class="text-[.82rem] text-sel-muted" id="sel-country-hint">Used for tax and invoicing. You can change it later in Billing.</p>
  </div>
</div></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#596073] uppercase">Three sizes</span><div class="rounded-2xl border border-[#e3e5ee] bg-white px-6 pt-[22px] pb-6 shadow-[0_1px_2px_rgba(20,24,40,.04)]">
  <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] items-start gap-4">
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-rows">Rows per page</label>
      <select class="sel-chevron block h-[34px] w-full cursor-pointer appearance-none rounded-lg border border-sel-line bg-white bg-position-[right_10px_center] bg-size-[14px] pr-[34px] pl-[11px] text-[.84rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-rows" name="rows"><option>10</option><option selected>25</option><option>50</option><option>100</option></select></div>
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-sort">Sort by</label>
      <select class="sel-chevron block h-11 w-full cursor-pointer appearance-none rounded-[10px] border border-sel-line bg-white pr-[42px] pl-3.5 text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-sort" name="sort"><option>Newest first</option><option>Oldest first</option><option>Price, low to high</option><option>Price, high to low</option></select></div>
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-plan">Plan</label>
      <select class="sel-chevron block h-[54px] w-full cursor-pointer appearance-none rounded-[13px] border border-sel-line bg-white bg-position-[right_18px_center] bg-size-[18px] pr-12 pl-[18px] text-[1.05rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-plan" name="plan"><option>Starter</option><option selected>Team</option><option>Business</option></select></div>
  </div>
</div></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#596073] uppercase">Leading icon, pill shape</span><div class="rounded-2xl border border-[#e3e5ee] bg-white px-6 pt-[22px] pb-6 shadow-[0_1px_2px_rgba(20,24,40,.04)]">
  <div class="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4">
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-currency">Currency</label><div class="relative">
      <svg class="pointer-events-none absolute top-1/2 left-[15px] size-[18px] -translate-y-1/2 text-sel-accent" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="2.5" y="6" width="19" height="12" rx="2"/><circle cx="12" cy="12" r="2.6"/><path d="M6 9.5v5M18 9.5v5"/></svg>
      <select class="sel-chevron block h-11 w-full cursor-pointer appearance-none rounded-full border border-sel-line bg-white bg-position-[right_16px_center] pr-11 pl-[43px] text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-currency" name="currency"><option value="EUR" selected>EUR — Euro</option><option value="GBP">GBP — Pound sterling</option><option value="USD">USD — US dollar</option><option value="SEK">SEK — Swedish krona</option></select></div></div>
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-lang">Language</label><div class="relative">
      <svg class="pointer-events-none absolute top-1/2 left-[15px] size-[18px] -translate-y-1/2 text-sel-accent" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9.5"/><path d="M2.5 12h19M12 2.5c2.6 2.8 3.8 6 3.8 9.5s-1.2 6.7-3.8 9.5c-2.6-2.8-3.8-6-3.8-9.5s1.2-6.7 3.8-9.5Z"/></svg>
      <select class="sel-chevron block h-11 w-full cursor-pointer appearance-none rounded-full border border-sel-line bg-white bg-position-[right_16px_center] pr-11 pl-[43px] text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none" id="sel-lang" name="language"><option value="en" selected>English</option><option value="de">Deutsch</option><option value="es">Español</option><option value="fr">Français</option><option value="lv">Latviešu</option></select></div></div>
  </div>
</div></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#596073] uppercase">Valid, invalid and disabled</span><div class="rounded-2xl border border-[#e3e5ee] bg-white px-6 pt-[22px] pb-6 shadow-[0_1px_2px_rgba(20,24,40,.04)]">
  <div class="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4">
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-ship">Delivery</label>
      <select class="sel-valid block h-11 w-full cursor-pointer appearance-none rounded-[10px] border border-sel-ok bg-white pr-[68px] pl-3.5 text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 focus-visible:shadow-[0_0_0_4px_rgba(21,128,61,.25)] focus-visible:outline-none motion-reduce:transition-none" id="sel-ship" name="delivery" aria-describedby="sel-ship-msg"><option>Standard — 3 to 5 days</option><option selected>Express — next day</option><option>Collect from store</option></select>
      <p class="text-[.82rem] font-medium text-sel-ok" id="sel-ship-msg">Arrives Thursday, 2 October</p></div>
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-size">Frame size</label>
      <select class="sel-invalid block h-11 w-full cursor-pointer appearance-none rounded-[10px] border border-sel-err bg-white pr-[68px] pl-3.5 text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 focus-visible:shadow-[0_0_0_4px_rgba(200,30,58,.22)] focus-visible:outline-none motion-reduce:transition-none" id="sel-size" name="size" required aria-invalid="true" aria-describedby="sel-size-msg"><option value="" selected>Choose a size</option><option>S — 160 to 170 cm</option><option>M — 170 to 180 cm</option><option>L — 180 to 190 cm</option></select>
      <p class="text-[.82rem] font-medium text-sel-err" id="sel-size-msg">Choose a frame size to continue.</p></div>
    <div class="grid min-w-0 gap-[7px]"><label class="text-[.9rem] font-semibold" for="sel-region">Data region</label>
      <select class="sel-chevron block h-11 w-full cursor-not-allowed appearance-none rounded-[10px] border border-[#cfd2dc] bg-[#f1f2f6] pr-[42px] pl-3.5 text-[.95rem] text-[#6b7080] [color-scheme:light]" id="sel-region" name="region" disabled aria-describedby="sel-region-hint"><option>EU — Frankfurt</option></select>
      <p class="text-[.82rem] text-sel-muted" id="sel-region-hint">Set when the workspace was created.</p></div>
  </div>
</div></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#596073] uppercase">Native multiple select</span><div class="rounded-2xl border border-[#e3e5ee] bg-white px-6 pt-[22px] pb-6 shadow-[0_1px_2px_rgba(20,24,40,.04)]">
  <div class="grid min-w-0 gap-[7px]">
    <label class="text-[.9rem] font-semibold" for="sel-topics">Newsletter topics</label>
    <select class="block w-full appearance-none overflow-y-auto rounded-[10px] border border-sel-line bg-white p-1.5 text-[.95rem] text-sel-ink shadow-[0_1px_2px_rgba(20,24,40,.06)] [color-scheme:light] transition-[border-color,box-shadow] duration-150 hover:border-[#5f6579] focus-visible:border-sel-accent focus-visible:shadow-[0_0_0_4px_rgba(79,70,229,.28)] focus-visible:outline-none motion-reduce:transition-none [&_option]:rounded-[7px] [&_option]:px-2.5 [&_option]:py-2 [&_option:checked]:bg-[linear-gradient(#e4e5ff,#e4e5ff)] [&_option:checked]:font-semibold [&_option:checked]:text-[#312e81]" id="sel-topics" name="topics" multiple size="6" aria-describedby="sel-topics-hint">
      <option value="product" selected>Product updates</option>
      <option value="engineering">Engineering blog</option>
      <option value="design" selected>Design notes</option>
      <option value="stories">Customer stories</option>
      <option value="events" selected>Events and webinars</option>
      <option value="jobs">Open roles</option>
    </select>
    <p class="text-[.82rem] text-sel-muted" id="sel-topics-hint">Hold Ctrl (or ⌘ on a Mac) to pick more than one.</p>
  </div>
</div></div>
CSS
@theme {
  --color-sel-accent: #4f46e5;
  --color-sel-line: #8a90a6;
  --color-sel-ink: #1e2233;
  --color-sel-muted: #596073;
  --color-sel-ok: #15803d;
  --color-sel-err: #c81e3a;
}
/* the chevron, and the chevron plus a status icon, as background images on the <select> */
@utility sel-chevron {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23596073' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 16px;
}
@utility sel-valid {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23596073' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2315803d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center, right 40px center; background-size: 16px, 16px;
}
@utility sel-invalid {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23596073' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23c81e3a' stroke-width='1.6'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M8 4.6v4' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.2' r='.6' fill='%23c81e3a'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center, right 40px center; background-size: 16px, 16px;
}

About this set

Five ways to dress a real select element without replacing it. Default with a hint is a country picker with optgroups and a helper line tied to it through aria-describedby. Three sizes puts a compact rows-per-page select, a standard sort select and a large plan select side by side, for toolbars, forms and hero filters. Leading icon, pill shape adds a currency or globe icon inside a rounded field. Valid, invalid and disabled covers the states a checkout needs: a green tick with a delivery date, a red warning with a message and aria-invalid, and a locked data region. Native multiple select styles a size=”6″ list whose picked rows get a tinted background, for short lists where a dropdown would hide the choices. Every control is the browser’s own select with appearance: none and a chevron drawn as a background image, so the option list, type-ahead, the mobile picker wheel and form submission all stay native. Use these whenever the options are plain text; reach for the richer sets in this pack only when options need avatars, icons, search or chips.

What’s included

  • Five variants: hint, three sizes, leading icon, validation states, native multiple list
  • Real select elements with appearance: none and an SVG chevron
  • Valid and invalid states with icons and messages tied through aria-describedby
  • Native option list, type-ahead and mobile pickers kept
  • No JavaScript

Accessibility

Every select has a visible label joined with for and id, and hints and error messages are linked through aria-describedby; the invalid select also carries aria-invalid. Keyboard behaviour is the browser's own, and focus draws a four-pixel ring in the accent colour. The border transition switches off under prefers-reduced-motion.

Customise it

Change --sel-accent, --sel-line, --sel-h and --sel-radius on .sel, and the stroke colour inside --sel-chev for the chevron. In Bootstrap the same variables sit on .sel over .form-select, with the chevron passed through --bs-form-select-bg-img; in Tailwind edit the --color-sel-* theme colours and the sel-chevron utility.