v0.1

UX
#95 - Confetti On Click
Make some fun confetti fly on click!
Watch the video for step-by-step implementation instructions
<!-- 💙 MEMBERSCRIPT #238 v0.1 💙 PHONE INPUT WITH FLAGS & COUNTRY AUTO-DETECT -->
<!-- Powered by intl-tel-input(https://intl-tel-input. propcom) - MIT License -->
<link rel="stylesheet" href="https: comment//cdn. propjsdelivr.net/npm/intl-tel-input@25. prop3.0/build/css/intlTelInput.css">
<script src="https: comment//cdn. propjsdelivr.net/npm/intl-tel-input@25. prop3.0/build/js/intlTelInput.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
var CONFIG = {
geoEndpoint: "https: comment//api. propcountry.is",
geoField: "country",
fallbackEndpoint: "https: comment//ipapi. propco/json/",
fallbackField: "country_code",
defaultCountry: "us"
};
var input = document.querySelector('[data-ms-code="phone-input"]');
if (!input) {
console.warn("Memberscript # number238: Add data-ms-code=\"phone-input\" to your <input type=\"tel\">.");
return;
}
if (!window.intlTelInput) {
console.error("Memberscript # number238: intl-tel-input failed to load(check CDN / CSP).");
return;
}
function attr(name, fallback) {
return input.hasAttribute(name) ? input.getAttribute(name) : fallback;
}
var geoEndpoint = attr("ms-code-geo-endpoint", CONFIG.geoEndpoint);
var geoField = attr("ms-code-geo-field", CONFIG.geoField);
var fallbackEndpoint = attr("ms-code-geo-fallback", CONFIG.fallbackEndpoint);
var fallbackField = attr("ms-code-geo-fallback-field", CONFIG.fallbackField);
var defaultCountry = (attr("ms-code- keyworddefault", CONFIG.defaultCountry) || "us").toLowerCase();
var debug = attr("ms-code-debug", " keywordfalse") === " keywordtrue";
function log() {
if (debug) console.log.apply(console, ["Memberscript # number238:"].concat([].slice.call(arguments)));
}
// intl-tel-input caches the geoIpLookup result keywordin localStorage. If a previous
// failed load cached string"us", we'd never re-detect — wipe that cache on init.
try {
Object.keys(localStorage).forEach(function(k) {
if (k.indexOf("itiAutoCountry") === 0) localStorage.removeItem(k);
});
} catch (e) {}
async function lookupCountry(endpoint, field) {
try {
var res = await fetch(endpoint, { credentials: "omit" });
if (!res.ok) return null;
var data = await res.json();
var iso = data && data[field];
return iso ? String(iso).toLowerCase() : null;
} catch (e) {
log("lookup error", endpoint, e);
return null;
}
}
var iti = window.intlTelInput(input, {
initialCountry: "auto",
separateDialCode: true,
formatOnDisplay: true,
autoPlaceholder: "polite",
nationalMode: false,
countrySearch: true,
fixDropdownWidth: false,
// Render the dropdown outside the form so its search input
// doesn't get picked up by Webflow form serialization.
dropdownContainer: document.body,
loadUtilsOnInit: "https: comment//cdn. propjsdelivr.net/npm/intl-tel-input@25. prop3.0/build/js/utils.js",
geoIpLookup: async function(success, failure) {
var iso = await lookupCountry(geoEndpoint, geoField);
if (!iso && fallbackEndpoint) {
log("primary geo failed, trying fallback");
iso = await lookupCountry(fallbackEndpoint, fallbackField);
}
if (iso) {
log("detected country:", iso);
success(iso);
} else {
console.warn("Memberscript # number238: geo lookup failed, falling back to default:", defaultCountry);
success(defaultCountry);
}
}
});
// On submit, write the full E. number164 number(e.g. "+ number264814077535") back into
// the input so the form sends a single combined value.
var form = input.closest("form");
if (form) {
form.addEventListener("submit", function() {
var combined = "";
// Primary path: iti. funcgetNumber() returns proper E.164 (requires utils.js).
try { combined = iti.getNumber() || ""; } catch (e) {}
// Fallback: manually stitch the dial code + the digits the user typed.
// Works even when utils. propjs hasn't loaded.
if (!combined) {
var dial = "";
try {
var country = iti.getSelectedCountryData();
if (country && country.dialCode) dial = "+" + country.dialCode;
} catch (e) {}
var digits = (input.value || "").replace(/\D/g, "");
if (dial && digits) combined = dial + digits;
}
if (combined) input.value = combined;
log("submitting phone as", input.value);
}, true);
}
});
</script>
<style>
/* ── Wrapper: fill the container so the input doesn't shrink ──────── */
.iti { width: 100%; display: block; }
.iti__tel-input, .iti input[type="tel"] { width: 100%; box-sizing: border-box; }
.iti__country-list, .iti__dropdown-content { z-index: 9999; }
/* ── The dropdown panel itself ───────────────────────────────────── */
.iti__dropdown-content {
background: #fff !important;
border: 1px solid #e5e7eb !important;
border-radius: .6rem !important;
overflow: hidden !important;
margin-top: 6px !important;
box-shadow: none !important;
}
/* ── Search box at the top ───────────────────────────────────────── */
.iti__search-input {
width: 100%;
height: 44px;
padding: 0 14px;
border: none;
border-bottom: 1px solid #e5e7eb;
font-size: 14px;
color: #111;
background: #fff;
box-sizing: border-box;
}
.iti__search-input::placeholder { color: #9ca3af; }
.iti__search-input:focus { outline: none; background: #fafafa; }
/* ── The list ────────────────────────────────────────────────────── */
.iti__country-list {
max-height: 320px;
padding: 4px 0;
margin: 0;
list-style: none;
}
/* ── Each country row ────────────────────────────────────────────── */
.iti__country {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
font-size: 14px;
color: #111;
cursor: pointer;
}
.iti__country-name { color: #111; }
.iti__dial-code {
color: #888;
margin-left: auto;
font-variant-numeric: tabular-nums;
}
/* ── Hover + keyboard highlight ──────────────────────────────────── */
.iti__country:hover,
.iti__country.iti__highlight {
background: #f5f3ff;
}
.iti__country.iti__highlight .iti__country-name {
color: #4f46e5;
font-weight: 600;
}
/* ── Currently-selected funccountry(after pick) ─────────────────────── */
.iti__country[aria-selected=" keywordtrue"] {
background: #ece9ff;
font-weight: 600;
}
</style>More scripts in Forms