Country Picker
A country field built from data, with a flag beside every name. A custom filter matches the name anywhere, or the exact country code, so de finds Germany.
No country matches your search
Code
The following example assumes that you have imported the components and set up the theme.
<div class="country-picker">7 collapsed lines
<label for="country">Country</label>
<sv-combobox id="country" name="country" placeholder="Search by name or code"> <sv-flyout class="country-flyout"> <p class="empty" data-combobox-no-results>No country matches your search</p> </sv-flyout> </sv-combobox></div>
<template id="country-option">4 collapsed lines
<button type="button" class="option"> <img alt="" loading="lazy" /> <span data-combobox-label></span> </button></template>
<script type="application/x-typescript" module>22 collapsed lines
import { countriesData } from "./countries-data.ts";
const countryCombobox = document.querySelector<Combobox>("#country")!; const countryFlyout = document.querySelector(".country-flyout")!; const optionTemplate = document.querySelector<HTMLTemplateElement>("#country-option")!; const flagsDir = new URL("@assets/flags/", import.meta.url);
for (const country of countriesData) { const option = optionTemplate.content.firstElementChild!.cloneNode(true) as HTMLButtonElement;
option.value = country.code; option.querySelector("img")!.src = `${flagsDir.href}${country.code}.png`; option.querySelector("[data-combobox-label]")!.textContent = country.label_en;
countryFlyout.append(option); }
// Match the name anywhere, or the exact country code countryCombobox.filter = (option, query) => { const lowerCaseQuery = query.toLowerCase(); return option.value === lowerCaseQuery || option.textContent!.toLowerCase().includes(lowerCaseQuery); };</script>
<style>42 collapsed lines
.country-picker { display: grid; gap: 0.5em; inline-size: min(100%, 22rem); margin-inline: auto; color: var(--sv-gray-2);
label { justify-self: start; cursor: pointer; }
.option { display: flex; gap: 0.75em; align-items: center; min-inline-size: 0;
img { flex: none; inline-size: 1.5em; block-size: 1.5em; border-radius: var(--sv-bdr-rad-sm); }
span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } }
.country-flyout::part(content) { max-block-size: min(var(--sv-anchor-available-height), 20rem); }
.empty { padding: 0.5em; margin: 0; color: var(--sv-gray-3); } }</style>