Alarm
Scheduled time-based alert system with localStorage persistence and repeat patterns
Overview
Alarm is a scheduled time-based alert system with localStorage persistence. Set alarms for specific times with repeat patterns, and they'll trigger even after page refresh or browser restart.
Key Features
- localStorage persistence - survives page reloads and browser restarts
- Singleton pattern - one instance manages all alarms globally
- Flexible repeat patterns: daily, weekdays, weekends, custom days, one-time
- Desktop notification integration when alarms trigger
- Optional sound playback on alarm trigger
- Snooze functionality with configurable duration
- Enable/disable individual alarms without deletion
- Automatic one-time alarm disabling after trigger
- Next alarm calculation and scheduling
When to Use Alarms
- Daily Routines: Morning routine, meal times, medication reminders
- Work Schedule: Meeting reminders, break times, end of day alerts
- Time Management: Task deadlines, time blocking, focus periods
- Fitness & Health: Workout times, water intake, posture checks
- Recurring Events: Weekly team calls, monthly reports, quarterly reviews
Basic Usage
// Create alarm manager (singleton)
const alarms = Domma.elements.alarm({
onTrigger: (alarm) => {
console.log('Alarm triggered:', alarm);
}
});
// Add an alarm
alarms.add({
time: '09:00', // 24-hour format
label: 'Morning Standup',
repeat: 'weekdays', // Monday-Friday
notification: true
});
// Alarms persist automatically to localStorage
// They'll trigger even after browser restart!
Quick Start
Set your first alarm in seconds. Alarms persist automatically.
Simplest One-Time Alarm
// Create alarm manager
const alarms = Domma.elements.alarm();
// Add one-time alarm (1 minute from now)
const now = new Date();
now.setMinutes(now.getMinutes() + 1);
const time = `${now.getHours()}:${String(now.getMinutes()).padStart(2, '0')}`;
alarms.add({
time: time,
label: 'Quick Reminder',
notification: true
});
<button type="button" class="btn btn-primary" id="quick-alarm">Set 1-Minute Alarm</button>
<p id="quick-status" class="mt-2"></p>/**
* Simplest One-Time Alarm - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to format alarm time (next minute)
function getNextMinuteTime(minutesAhead = 1) {
return D().add(minutesAhead, 'minutes').format('HH:mm');
}
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
// Quick Start demos
$(root).find('#quick-alarm').on('click', () => {
const time = getNextMinuteTime(1);
alarmManager.add({
time: time,
label: 'Quick Reminder',
notification: true
});
$(root).find('#quick-status').text(`✓ Alarm set for ${time}`).removeClass().addClass('mt-2 text-success');
});
}Simplest Daily Alarm
// Daily morning alarm
alarms.add({
time: '08:00',
label: 'Morning Routine',
repeat: 'daily',
notification: true
});
<button type="button" class="btn btn-primary" id="quick-daily">Set Daily 8 AM Alarm</button>
<p id="daily-status" class="mt-2"></p>/**
* Simplest Daily Alarm - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
$(root).find('#quick-daily').on('click', () => {
alarmManager.add({
time: '08:00',
label: 'Morning Routine',
repeat: 'daily',
notification: true
});
$(root).find('#daily-status').text('✓ Daily alarm set for 08:00').removeClass().addClass('mt-2 text-success');
});
}Step-by-Step Tutorial
Build a complete alarm system with multiple alarms, notifications, and management UI.
Step 1: Initialize Alarm Manager
const alarmManager = Domma.elements.alarm({
storageKey: 'my-app-alarms', // Custom storage key
checkInterval: 30000, // Check every 30 seconds
onTrigger: (alarm) => {
console.log('Alarm triggered:', alarm);
// Show visual feedback
showAlarmModal(alarm);
},
onAlarmAdd: (alarm) => {
console.log('Alarm added:', alarm);
updateAlarmList();
},
onAlarmRemove: (alarm) => {
console.log('Alarm removed:', alarm);
updateAlarmList();
}
});
Step 2: Add Multiple Alarms
// Morning routine
alarmManager.add({
time: '07:00',
label: 'Wake Up',
repeat: 'weekdays',
notification: true,
notificationOptions: {
title: 'Good Morning!',
body: 'Time to start your day',
requireInteraction: true
}
});
// Lunch break
alarmManager.add({
time: '12:30',
label: 'Lunch Break',
repeat: 'weekdays',
notification: true
});
// End of work
alarmManager.add({
time: '17:00',
label: 'End of Workday',
repeat: 'weekdays',
notification: true
});
Step 3: Display and Manage Alarms
function updateAlarmList() {
const alarms = alarmManager.getAlarms();
const listEl = $('#alarm-list')[0];
listEl.innerHTML = alarms.map(alarm => `
${alarm.time}
${alarm.label}
${getRepeatText(alarm.repeat)}
${alarm.enabled ? 'Disable' : 'Enable'}
Delete
`).join('');
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAlarmList();
}
function deleteAlarm(id) {
alarmManager.remove(id);
updateAlarmList();
}
<button type="button" class="btn btn-primary" id="tutorial-add-morning">Add Morning Alarm</button>
<button type="button" class="btn btn-primary" id="tutorial-add-lunch">Add Lunch Alarm</button>
<button type="button" class="btn btn-primary" id="tutorial-add-evening">Add Evening Alarm</button>
<div id="tutorial-alarm-list" class="alarm-list-style"></div>/**
* Tutorial Demo: Alarm Manager - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
// Tutorial demos
$(root).find('#tutorial-add-morning').on('click', () => {
alarmManager.add({
time: '07:00',
label: 'Morning Alarm',
repeat: 'weekdays',
notification: true
});
});
$(root).find('#tutorial-add-lunch').on('click', () => {
alarmManager.add({
time: '12:30',
label: 'Lunch Break',
repeat: 'weekdays',
notification: true
});
});
$(root).find('#tutorial-add-evening').on('click', () => {
alarmManager.add({
time: '17:00',
label: 'End of Day',
repeat: 'weekdays',
notification: true
});
});
// Initial load
updateAllLists();
}Real-World Examples
1. Workday Schedule
const workdayAlarms = [
{ time: '09:00', label: 'Morning Standup', repeat: 'weekdays' },
{ time: '10:30', label: 'Focus Time Starts', repeat: 'weekdays' },
{ time: '12:00', label: 'Lunch Break', repeat: 'weekdays' },
{ time: '15:00', label: 'Afternoon Check-in', repeat: 'weekdays' },
{ time: '17:00', label: 'End of Day', repeat: 'weekdays' }
];
const alarms = Domma.elements.alarm();
workdayAlarms.forEach(alarm => {
alarms.add({
...alarm,
notification: true,
notificationOptions: {
requireInteraction: true
}
});
});
<button type="button" class="btn btn-primary" id="example-workday">Setup Workday Alarms</button>
<div id="example-workday-list" class="alarm-list-style"></div>/**
* 1. Workday Schedule - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
// Example demos
$(root).find('#example-workday').on('click', () => {
['09:00', '12:00', '15:00', '17:00'].forEach((time, i) => {
const labels = ['Standup', 'Lunch', 'Break', 'End of Day'];
alarmManager.add({
time: time,
label: labels[i],
repeat: 'weekdays',
notification: true
});
});
});
}2. Fitness Reminders
// Custom workout schedule
alarms.add({
time: '06:30',
label: 'Morning Workout',
repeat: ['mon', 'wed', 'fri'], // Custom days
notification: true,
sound: true,
soundUrl: '/sounds/workout-bell.mp3'
});
alarms.add({
time: '12:00',
label: 'Lunchtime Walk',
repeat: 'weekdays',
notification: true
});
alarms.add({
time: '15:00',
label: 'Posture Check',
repeat: 'daily',
notification: true
});
<button type="button" class="btn btn-primary" id="example-fitness">Setup Fitness Alarms</button>
<div id="example-fitness-list" class="alarm-list-style"></div>/**
* 2. Fitness Reminders - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
$(root).find('#example-fitness').on('click', () => {
alarmManager.add({time: '06:30', label: 'Workout', repeat: ['mon', 'wed', 'fri'], notification: true});
alarmManager.add({time: '12:00', label: 'Walk', repeat: 'weekdays', notification: true});
});
}3. Medication Reminders
const medications = [
{ time: '08:00', label: 'Morning Medication', repeat: 'daily' },
{ time: '20:00', label: 'Evening Medication', repeat: 'daily' }
];
medications.forEach(med => {
alarms.add({
...med,
notification: true,
notificationOptions: {
title: 'Medication Reminder',
body: med.label,
requireInteraction: true, // Must be acknowledged
icon: '/icons/medical.png'
}
});
});
<button type="button" class="btn btn-primary" id="example-medication">Setup Medication Reminders</button>
<div id="example-medication-list" class="alarm-list-style"></div>/**
* 3. Medication Reminders - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
$(root).find('#example-medication').on('click', () => {
alarmManager.add({time: '08:00', label: 'Morning Meds', repeat: 'daily', notification: true});
alarmManager.add({time: '20:00', label: 'Evening Meds', repeat: 'daily', notification: true});
});
}4. Snooze Functionality
const alarms = Domma.elements.alarm({
onTrigger: async (alarm) => {
// Show modal with snooze option
const result = await Domma.elements.confirm(
`Alarm: ${alarm.label}\nSnooze for 10 minutes?`,
{
title: 'Alarm Triggered',
confirmText: 'Snooze',
cancelText: 'Dismiss'
}
);
if (result) {
// Snooze for 10 minutes
alarms.snooze(alarm.id, 600000);
console.log('Alarm snoozed');
} else {
// User dismissed - alarm will re-trigger based on repeat
console.log('Alarm dismissed');
}
}
});
<button type="button" class="btn btn-primary" id="example-snooze">Test Snooze (1 min alarm)</button>
<p id="snooze-status" class="mt-2"></p>/**
* 4. Snooze Functionality - from public/showcase/elements/alarm.
*/
export function mount(root) {
const alarmManager = E.alarm({
onTrigger: async (alarm) => {
console.log('Alarm triggered:', alarm);
await E.alert(
`Alarm: ${alarm.label}\nTime: ${alarm.time}`,
{title: 'Alarm Triggered'}
);
},
onAlarmAdd: () => updateAllLists(),
onAlarmRemove: () => updateAllLists()
});
// Helper to format alarm time (next minute)
function getNextMinuteTime(minutesAhead = 1) {
return D().add(minutesAhead, 'minutes').format('HH:mm');
}
// Helper to render alarm list
function renderAlarmList(containerId, alarms) {
const $container = $('#' + containerId);
if (!alarms || alarms.length === 0) {
$container.html('<p class="text-muted">No alarms set</p>');
return;
}
$container.html(alarms.map(alarm => `
<div class="alarm-item-style ${alarm.enabled ? '' : 'disabled'}">
<div class="alarm-info-style">
<div class="alarm-time-style">${alarm.time}</div>
<div class="alarm-label-style">${alarm.label}</div>
<div class="alarm-repeat-style">${getRepeatText(alarm.repeat)}</div>
</div>
<div class="alarm-controls-style">
<button class="btn btn-sm btn-secondary" onclick="toggleAlarm('${alarm.id}')">
${alarm.enabled ? 'Disable' : 'Enable'}
</button>
<button class="btn btn-sm btn-danger" onclick="deleteAlarm('${alarm.id}')">Delete</button>
</div>
</div>
`).join(''));
}
function getRepeatText(repeat) {
if (!repeat) return 'One-time';
if (repeat === 'daily') return 'Daily';
if (repeat === 'weekdays') return 'Weekdays';
if (repeat === 'weekends') return 'Weekends';
if (Array.isArray(repeat)) return repeat.join(', ');
return repeat;
}
function toggleAlarm(id) {
alarmManager.toggle(id);
updateAllLists();
};
function deleteAlarm(id) {
alarmManager.remove(id);
updateAllLists();
};
function updateAllLists() {
const allAlarms = alarmManager.getAlarms();
['tutorial-alarm-list', 'example-workday-list', 'example-fitness-list', 'example-medication-list'].forEach(id => {
if ($('#' + id).length) renderAlarmList(id, allAlarms);
});
}
$(root).find('#example-snooze').on('click', () => {
const time = getNextMinuteTime(1);
const alarm = alarmManager.add({
time: time,
label: 'Snooze Test',
notification: true
});
$(root).find('#snooze-status').text(`Test alarm set for ${time}. Will trigger with snooze option.`).removeClass().addClass('mt-2 text-info');
});
}Best Practices
✅ Do's
- Use 24-hour time format - Alarms use HH:MM format (00:00 to 23:59)
- Provide descriptive labels - Help users identify alarms in the list
- Use appropriate repeat patterns - weekdays for work, daily for habits, custom for flexible schedules
- Enable requireInteraction for important alarms - Medication, meetings, critical tasks
- Implement snooze for user convenience - Give users option to delay alarms
- Show next alarm prominently - Use getNextAlarm() to display upcoming alert
- Provide alarm management UI - List, enable/disable, delete options
- Test alarm timing - Set test alarms 1-2 minutes ahead to verify functionality
❌ Don'ts
- Don't set too many alarms - Users will experience alarm fatigue
- Don't use 12-hour time - Always convert to 24-hour format (14:30 not 2:30 PM)
- Don't forget to disable one-time alarms - System auto-disables after trigger
- Don't rely solely on alarms for critical timing - Consider server-side scheduling
- Don't use very short check intervals - 30-60 seconds is sufficient, 5s wastes CPU
- Don't override user's alarm preferences - Let users manage their own alarms
Persistence Pattern
// Alarms automatically persist, but good to verify
function setupAlarms() {
const alarms = Domma.elements.alarm();
// Check if alarms already exist (from previous session)
const existing = alarms.getAlarms();
if (existing.length === 0) {
// First time setup
setupDefaultAlarms(alarms);
} else {
// Alarms loaded from localStorage
console.log(`Loaded ${existing.length} alarms from storage`);
displayAlarms(existing);
}
}
Next Alarm Display Pattern
function showNextAlarm() {
const alarms = Domma.elements.alarm();
const next = alarms.getNextAlarm();
if (next) {
const triggerDate = new Date(next.nextTrigger);
const timeUntil = triggerDate - new Date();
const hours = Math.floor(timeUntil / 3600000);
const minutes = Math.floor((timeUntil % 3600000) / 60000);
$('#next-alarm')[0].innerHTML = `
Next Alarm: ${next.label}
In ${hours}h ${minutes}m (${next.time})
`;
} else {
$('#next-alarm')[0].textContent = 'No alarms set';
}
}
// Update every minute
setInterval(showNextAlarm, 60000);
showNextAlarm();
Complete API Reference
Factory Method
// Singleton - always returns same instance
elements.alarm(options)
Options
| Option | Type | Default | Description |
|---|---|---|---|
alarms |
array | [] | Initial alarms to add (if not in storage) |
timezone |
string | 'local' | Timezone for alarm calculations |
checkInterval |
number | 30000 | Check frequency in milliseconds |
storageKey |
string | 'domma-alarms' | localStorage key for persistence |
onTrigger |
function | null | Callback when alarm triggers (alarm) |
onSnooze |
function | null | Callback when alarm snoozed (alarm, duration) |
onAlarmAdd |
function | null | Callback when alarm added (alarm) |
onAlarmRemove |
function | null | Callback when alarm removed (alarm) |
Alarm Object Structure
{
id: 'alarm-1', // Auto-generated
time: '14:30', // HH:MM format (24-hour)
label: 'Meeting', // Alarm description
enabled: true, // Active state
repeat: 'weekdays', // Repeat pattern (see below)
notification: true, // Show desktop notification
notificationOptions: {}, // Notification API options
sound: false, // Play sound on trigger
soundUrl: null, // URL to sound file
lastTriggered: 1234567890, // Timestamp of last trigger
snoozedUntil: null // Snooze expiration timestamp
}
Repeat Patterns
// String patterns
'daily' // Every day
'weekdays' // Monday-Friday
'weekends' // Saturday-Sunday
// Array of days (lowercase, 3-letter)
['mon', 'wed', 'fri'] // Custom days
['tue', 'thu'] // Tuesday and Thursday
// One-time alarm
null // No repeat (auto-disables after trigger)
Instance Methods
// Add/Remove alarms
alarms.add(alarm) // Returns alarm with id
alarms.remove(id) // Returns boolean
alarms.update(id, changes) // Returns updated alarm or null
// Enable/Disable
alarms.enable(id) // Returns boolean
alarms.disable(id) // Returns boolean
alarms.toggle(id) // Returns new enabled state
// Snooze
alarms.snooze(id, duration) // Duration in ms, default 300000 (5 min)
// Query
alarms.getAlarms() // Returns array of all alarms
alarms.getAlarm(id) // Returns alarm or null
alarms.getNextAlarm() // Returns next alarm with nextTrigger date
// Management
alarms.clearAll() // Remove all alarms
alarms.destroy() // Stop checking and cleanup
Declarative Configuration
While alarms are typically managed programmatically, you can initialize the alarm system via config.
Initialize with Default Alarms
$.setup({
body: {
// No selector needed - alarm is singleton
}
});
// Then use programmatically
const alarms = Domma.elements.alarm({
alarms: [
{ time: '09:00', label: 'Daily Standup', repeat: 'weekdays' },
{ time: '17:00', label: 'End of Day', repeat: 'weekdays' }
],
onTrigger: (alarm) => {
Domma.elements.notify(alarm.label, {
body: `Alarm at ${alarm.time}`,
requireInteraction: true
});
}
});
CSS Customisation
Override these CSS variables to customise Alarm appearance and match your design system.
| Variable | Default | Controls |
|---|---|---|
--dm-success |
var(--dm-green-600) |
Active alarm colour |
--dm-warning |
var(--dm-amber-500) |
Upcoming alarm colour |
--dm-secondary |
var(--dm-slate-600) |
Disabled alarm colour |
--dm-surface |
var(--dm-white) |
Alarm card background |
Example Override
:root {
/* Custom alarm colours */
--dm-success: #10b981;
--dm-warning: #f59e0b;
}
Full CSS Customisation Cheat-Sheet →
Related Components
Alarm works seamlessly with other Domma components for complete scheduling solutions.
<div class="grid grid-cols-1 grid-cols-md-2 gap-4"><div class="related-card-style">
<h4>DesktopNotification</h4>
<p>Desktop alerts when alarms trigger</p>
<a href="/showcase/elements/notification" class="btn btn-sm btn-outline">View Notification →</a>
</div>
<div class="related-card-style">
<h4>Timer</h4>
<p>Countdown timers for immediate timing needs</p>
<a href="/showcase/elements/timer" class="btn btn-sm btn-outline">View Timer →</a>
</div>
<div class="related-card-style">
<h4>Modal</h4>
<p>Display alarm details and snooze options</p>
<a href="/showcase/elements/modal" class="btn btn-sm btn-outline">View Modal →</a>
</div>
<div class="related-card-style">
<h4>Form Elements</h4>
<p>Time pickers for setting alarm times</p>
<a href="/showcase/elements/forms" class="btn btn-sm btn-outline">View Forms →</a>
</div>
</div>When to Use Each
- Alarm: Scheduled events at specific times of day (09:00, 14:30, etc.)
- Timer: Countdown from current time (5 minutes from now, 1 hour, etc.)
- Notification: Immediate desktop alerts for any event