A day's times, anywhere
Pick a city and a country's method and see the timetable that country prints — with the next prayer counting down and the qibla bearing.
<div class="demo">
<div class="demo-row">
<div class="demo-field">
<label class="demo-label" for="city">City</label>
<select id="city" class="demo-input"></select>
</div>
<div class="demo-field">
<label class="demo-label" for="madhab">Asr</label>
<select id="madhab" class="demo-input">
<option value="standard">Standard</option>
<option value="hanafi">Hanafi</option>
</select>
</div>
</div>
<div class="demo-card">
<div class="demo-kv" id="times"></div>
</div>
<div class="demo-row">
<p class="demo-out" id="next"></p>
<p class="demo-out" id="qibla"></p>
</div>
<p class="demo-hint" id="method"></p>
</div>
import { compassPoint, currentPrayer, distanceToKaaba, formatTimes, nextPrayer, prayerTimes, qibla } from 'https://devix.pk/cdn/oss/prayer-times@1.0.0/index.js';
const CITIES = [
['Dubai', 25.2048, 55.2708, 'AE', 'Asia/Dubai'],
['Makkah', 21.3891, 39.8579, 'SA', 'Asia/Riyadh'],
['Karachi', 24.8607, 67.0011, 'PK', 'Asia/Karachi'],
['Cairo', 30.0444, 31.2357, 'EG', 'Africa/Cairo'],
['Istanbul', 41.0082, 28.9784, 'TR', 'Europe/Istanbul'],
['London', 51.5074, -0.1278, 'GB', 'Europe/London'],
['New York', 40.7128, -74.006, 'US', 'America/New_York'],
['Jakarta', -6.2088, 106.8456, 'ID', 'Asia/Jakarta'],
['Tromsø', 69.6492, 18.9553, 'NO', 'Europe/Oslo'],
];
const NAMES = { fajr: 'Fajr', sunrise: 'Sunrise', dhuhr: 'Dhuhr', asr: 'Asr', maghrib: 'Maghrib', isha: 'Isha' };
const cityField = document.getElementById('city');
const madhabField = document.getElementById('madhab');
for (const [name] of CITIES) {
const option = document.createElement('option');
option.value = name;
option.textContent = name;
cityField.append(option);
}
function render() {
const [name, latitude, longitude, country, zone] = CITIES.find(([city]) => city === cityField.value) ?? CITIES[0];
const options = { country, madhab: madhabField.value };
const times = prayerTimes({ latitude, longitude }, new Date(), options);
const formatted = formatTimes(times, zone);
const upcoming = nextPrayer({ latitude, longitude }, options);
const now = currentPrayer({ latitude, longitude }, options);
const board = document.getElementById('times');
board.textContent = '';
for (const [key, label] of Object.entries(NAMES)) {
const cell = document.createElement('div');
cell.className = upcoming?.name === key ? 'is-next' : '';
cell.innerHTML = `<span class="demo-hint">${label}</span><br><b>${formatted[key]}</b>`;
board.append(cell);
}
document.getElementById('next').textContent = upcoming
? `Next: ${NAMES[upcoming.name]} in ${Math.floor(upcoming.inMinutes / 60)}h ${upcoming.inMinutes % 60}m${now ? ` · now: ${NAMES[now]}` : ''}`
: '';
const bearing = qibla(latitude, longitude);
document.getElementById('qibla').textContent = `Qibla ${bearing.toFixed(1)}° ${compassPoint(bearing)} · ${distanceToKaaba(latitude, longitude).toLocaleString()} km`;
document.getElementById('method').textContent = `${times.method.name}${times.estimated ? ' — the sun does not reach the angle here today, so Fajr and Isha are estimated.' : ''}`;
}
cityField.addEventListener('change', render);
madhabField.addEventListener('change', render);
render();
setInterval(render, 30_000);
#times { gap: 12px 22px; }
#times b { font-size: 16px; font-variant-numeric: tabular-nums; }
#times .is-next b { color: var(--demo-accent); }
#next, #qibla { flex: 1; min-width: 180px; }