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
});
Simplest One-Time Alarm

<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
});
Simplest Daily Alarm

<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();
}
Tutorial Demo: Alarm Manager
<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
        }
    });
});
1. Workday Schedule
<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
});
2. Fitness Reminders
<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'
        }
    });
});
3. Medication Reminders
<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');
        }
    }
});
4. Snooze Functionality

<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.

Related Components
<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