* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
color: white;
margin-bottom: 40px;
}
.header h1 {
font-size: 42px;
font-weight: 700;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}
.header p {
font-size: 18px;
opacity: 0.9;
}
.examples-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.format-card {
background: white;
border-radius: 16px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
.card-title {
display: flex;
align-items: center;
gap: 12px;
font-size: 20px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 8px;
}
.card-title ion-icon {
font-size: 28px;
color: #3498db;
}
.card-description {
color: #7f8c8d;
font-size: 14px;
margin-bottom: 20px;
}
.format-badge {
display: inline-block;
background: #e3f2fd;
color: #1976d2;
font-size: 12px;
font-weight: 600;
padding: 4px 12px;
border-radius: 12px;
margin-bottom: 15px;
}
.input-group {
margin-bottom: 20px;
}
.input-label {
display: block;
font-size: 14px;
font-weight: 600;
color: #2c3e50;
margin-bottom: 8px;
}
.input-wrapper {
position: relative;
}
.phone-input {
width: 100%;
padding: 14px 16px 14px 50px;
border: 2px solid #e9ecef;
border-radius: 10px;
font-size: 18px;
font-weight: 500;
transition: all 0.3s;
font-family: 'Courier New', monospace;
}
.phone-input:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.1);
}
.phone-input.valid {
border-color: #27ae60;
}
.phone-input.invalid {
border-color: #e74c3c;
}
.input-icon {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
font-size: 24px;
color: #3498db;
pointer-events: none;
}
.output-display {
background: #f8f9fa;
padding: 16px;
border-radius: 10px;
margin-bottom: 15px;
}
.output-label {
font-size: 12px;
font-weight: 600;
color: #7f8c8d;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 6px;
}
.output-value {
font-size: 20px;
font-weight: 600;
color: #2c3e50;
font-family: 'Courier New', monospace;
}
.info-box {
background: #e8f5e9;
border-left: 4px solid #27ae60;
padding: 12px 16px;
border-radius: 6px;
margin-top: 15px;
}
.info-box p {
font-size: 13px;
color: #2e7d32;
line-height: 1.5;
}
.country-selector {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.country-btn {
flex: 1;
padding: 10px;
border: 2px solid #e9ecef;
border-radius: 8px;
background: white;
cursor: pointer;
font-size: 14px;
font-weight: 600;
color: #7f8c8d;
transition: all 0.2s;
}
.country-btn:hover {
border-color: #3498db;
}
.country-btn.active {
background: #3498db;
color: white;
border-color: #3498db;
}
.demo-section {
background: white;
border-radius: 16px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
.demo-title {
font-size: 24px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 12px;
}
.demo-title ion-icon {
font-size: 32px;
color: #3498db;
}
.validation-result {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
border-radius: 8px;
margin-top: 10px;
font-size: 14px;
font-weight: 600;
}
.validation-result.success {
background: #e8f5e9;
color: #2e7d32;
}
.validation-result.error {
background: #ffebee;
color: #c62828;
}
.validation-result ion-icon {
font-size: 20px;
}
@media (max-width: 768px) {
.header h1 {
font-size: 32px;
}
.examples-grid {
grid-template-columns: 1fr;
}
.phone-input {
font-size: 16px;
}
.output-value {
font-size: 18px;
}
}
// US Phone Format: (XXX) XXX-XXXX
function formatUSPhone(value) {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,3})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = '';
if (match[1]) formatted += '(' + match[1];
if (match[1].length === 3) formatted += ') ';
if (match[2]) formatted += match[2];
if (match[2].length === 3) formatted += '-';
if (match[3]) formatted += match[3];
return formatted;
}
return value;
}
// International Format: +X (XXX) XXX-XXXX
function formatInternationalPhone(value) {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,1})(\d{0,3})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = '';
if (match[1]) formatted += '+' + match[1];
if (match[2]) formatted += ' (' + match[2];
if (match[2].length === 3) formatted += ') ';
if (match[3]) formatted += match[3];
if (match[3].length === 3) formatted += '-';
if (match[4]) formatted += match[4];
return formatted;
}
return value;
}
// Dot Format: XXX.XXX.XXXX
function formatDotPhone(value) {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,3})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += '.' + match[2];
if (match[3]) formatted += '.' + match[3];
return formatted;
}
return value;
}
// Dash Format: XXX-XXX-XXXX
function formatDashPhone(value) {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,3})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += '-' + match[2];
if (match[3]) formatted += '-' + match[3];
return formatted;
}
return value;
}
// Country-specific formats
const countryFormats = {
us: {
format: (value) => {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,3})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += '-' + match[2];
if (match[3]) formatted += '-' + match[3];
return formatted;
}
return value;
},
validate: (value) => /^\d{3}-\d{3}-\d{4}$/.test(value),
placeholder: '555-123-4567'
},
uk: {
format: (value) => {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,4})(\d{0,3})(\d{0,4})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += ' ' + match[2];
if (match[3]) formatted += ' ' + match[3];
return formatted;
}
return value;
},
validate: (value) => /^\d{4}\s\d{3}\s\d{4}$/.test(value),
placeholder: '0123 456 7890'
},
pk: {
format: (value) => {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,4})(\d{0,7})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += '-' + match[2];
return formatted;
}
return value;
},
validate: (value) => /^\d{4}-\d{7}$/.test(value),
placeholder: '0300-1234567'
},
au: {
format: (value) => {
const cleaned = value.replace(/\D/g, '');
const match = cleaned.match(/^(\d{0,4})(\d{0,3})(\d{0,3})$/);
if (match) {
let formatted = match[1];
if (match[2]) formatted += ' ' + match[2];
if (match[3]) formatted += ' ' + match[3];
return formatted;
}
return value;
},
validate: (value) => /^\d{4}\s\d{3}\s\d{3}$/.test(value),
placeholder: '0412 345 678'
}
};
// US Phone
const usPhone = document.getElementById('usPhone');
const usOutput = document.getElementById('usOutput');
usPhone.addEventListener('input', (e) => {
const formatted = formatUSPhone(e.target.value);
e.target.value = formatted;
usOutput.textContent = formatted || '(___) ___-____';
const cleaned = formatted.replace(/\D/g, '');
if (cleaned.length === 10) {
e.target.classList.add('valid');
} else {
e.target.classList.remove('valid');
}
});
// International Phone
const intlPhone = document.getElementById('intlPhone');
const intlOutput = document.getElementById('intlOutput');
intlPhone.addEventListener('input', (e) => {
const formatted = formatInternationalPhone(e.target.value);
e.target.value = formatted;
intlOutput.textContent = formatted || '+_ (___) ___-____';
const cleaned = formatted.replace(/\D/g, '');
if (cleaned.length === 11) {
e.target.classList.add('valid');
} else {
e.target.classList.remove('valid');
}
});
// Dot Phone
const dotPhone = document.getElementById('dotPhone');
const dotOutput = document.getElementById('dotOutput');
dotPhone.addEventListener('input', (e) => {
const formatted = formatDotPhone(e.target.value);
e.target.value = formatted;
dotOutput.textContent = formatted || '___.___._____';
const cleaned = formatted.replace(/\D/g, '');
if (cleaned.length === 10) {
e.target.classList.add('valid');
} else {
e.target.classList.remove('valid');
}
});
// Dash Phone
const dashPhone = document.getElementById('dashPhone');
const dashOutput = document.getElementById('dashOutput');
dashPhone.addEventListener('input', (e) => {
const formatted = formatDashPhone(e.target.value);
e.target.value = formatted;
dashOutput.textContent = formatted || '___-___-____';
const cleaned = formatted.replace(/\D/g, '');
if (cleaned.length === 10) {
e.target.classList.add('valid');
} else {
e.target.classList.remove('valid');
}
});
// Advanced Multi-Country Formatter
const advancedPhone = document.getElementById('advancedPhone');
const advancedOutput = document.getElementById('advancedOutput');
const validationResult = document.getElementById('validationResult');
const countryBtns = document.querySelectorAll('.country-btn');
let currentCountry = 'us';
countryBtns.forEach(btn => {
btn.addEventListener('click', () => {
countryBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentCountry = btn.dataset.country;
advancedPhone.placeholder = countryFormats[currentCountry].placeholder;
advancedPhone.value = '';
advancedOutput.textContent = 'Waiting for input...';
validationResult.innerHTML = '';
});
});
advancedPhone.addEventListener('input', (e) => {
const formatter = countryFormats[currentCountry];
const formatted = formatter.format(e.target.value);
e.target.value = formatted;
advancedOutput.textContent = formatted || 'Waiting for input...';
const isValid = formatter.validate(formatted);
if (formatted.length > 0) {
if (isValid) {
e.target.classList.add('valid');
e.target.classList.remove('invalid');
validationResult.innerHTML = `
<div class="validation-result success">
<ion-icon name="checkmark-circle"></ion-icon>
Valid phone number format
</div>
`;
} else {
e.target.classList.remove('valid');
e.target.classList.add('invalid');
validationResult.innerHTML = `
<div class="validation-result error">
<ion-icon name="close-circle"></ion-icon>
Incomplete phone number
</div>
`;
}
} else {
e.target.classList.remove('valid', 'invalid');
validationResult.innerHTML = '';
}
});
No comments yet. Be the first!