repeating-countdown
v1.0.2
Published
Zero-dependency countdown utility with React hooks and components that resets on schedule with timezone-safe calculations
Maintainers
Readme
Repeating Countdown
A zero-dependency countdown utility with React hooks and components that resets on schedule with timezone-safe calculations.
Features
- ⏰ Zero Dependencies - No external dependencies for core functionality
- 🔄 Repeating Countdowns - Automatically resets on schedule
- 🌍 Timezone Safe - Proper timezone handling and server sync
- ⚛️ React Ready - Custom hook and widget component
- 🎨 Beautiful UI - Human-friendly display with progress bar
- ⏸️ Pause/Resume - Full control over countdown state
- 📱 Responsive - Works on all screen sizes
- 🔧 TypeScript - Full type safety and IntelliSense support
Installation
npm install repeating-countdownQuick Start
Basic Usage
import React from 'react';
import { CountdownWidget } from 'repeating-countdown';
function App() {
const config = {
duration: 3 * 24 * 60 * 60 * 1000, // 3 days
autoReset: true
};
return <CountdownWidget config={config} />;
}Using the Hook
import React from 'react';
import { useRepeatingCountdown } from 'repeating-countdown';
function CustomCountdown() {
const {
timeLeft,
isPaused,
isCompleted,
progress,
timeDisplay,
start,
pause,
resume,
reset
} = useRepeatingCountdown({
duration: 1000 * 60 * 60, // 1 hour
autoReset: true,
onComplete: () => console.log('Countdown completed!'),
onReset: () => console.log('Countdown reset!')
});
return (
<div>
<h2>{timeDisplay.formatted}</h2>
<div>Progress: {progress.toFixed(1)}%</div>
<div>Status: {isCompleted ? 'Completed' : isPaused ? 'Paused' : 'Running'}</div>
<button onClick={isPaused ? resume : pause}>
{isPaused ? 'Start' : 'Pause'}
</button>
<button onClick={reset}>Reset</button>
</div>
);
}API Reference
CountdownWidget
A pre-built React component with a beautiful UI.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| config | CountdownConfig | - | Countdown configuration |
| className | string | '' | Custom CSS class name |
| showControls | boolean | true | Whether to show pause/resume/reset controls |
| formatTime | (time: TimeDisplay) => string | Default formatter | Custom time formatting function |
| showProgress | boolean | true | Whether to show progress bar |
| progressColor | string | '#3b82f6' | Progress bar color |
Example
<CountdownWidget
config={{
duration: 1000 * 60 * 60, // 1 hour
timezoneOffset: -300, // EST
autoReset: true
}}
showControls={true}
showProgress={true}
progressColor="#10b981"
className="my-countdown"
/>useRepeatingCountdown Hook
A React hook for managing countdown state.
Parameters
config: CountdownConfig- Countdown configuration
Returns
{
// State
timeLeft: number; // Time remaining in milliseconds
isPaused: boolean; // Whether countdown is paused
isCompleted: boolean; // Whether countdown has completed
nextResetTime: Date; // Time when countdown will reset
progress: number; // Progress percentage (0-100)
timeDisplay: TimeDisplay; // Formatted time display
// Controls
start: () => void; // Start the countdown
pause: () => void; // Pause the countdown
resume: () => void; // Resume the countdown
reset: () => void; // Reset the countdown
setDuration: (duration: number) => void; // Set new duration
}CountdownConfig
Configuration object for countdown behavior.
interface CountdownConfig {
duration: number; // Duration in milliseconds
timezoneOffset?: number; // Timezone offset in minutes (e.g., -300 for EST)
serverOffset?: number; // Server time offset in milliseconds
autoReset?: boolean; // Whether to auto-reset when complete
onComplete?: () => void; // Callback when countdown reaches zero
onReset?: () => void; // Callback when countdown resets
}TimeDisplay
Formatted time display object.
interface TimeDisplay {
days: number; // Days remaining
hours: number; // Hours remaining
minutes: number; // Minutes remaining
seconds: number; // Seconds remaining
totalMs: number; // Total milliseconds remaining
formatted: string; // Human-readable string (e.g., "2d 03h 45m 30s")
}Advanced Examples
Server-Synced Countdown
import { useRepeatingCountdown } from 'repeating-countdown';
function ServerSyncedCountdown() {
const config = {
duration: 1000 * 60 * 60, // 1 hour
serverOffset: 5000, // 5 seconds ahead of local time
timezoneOffset: -300, // EST
autoReset: true
};
const countdown = useRepeatingCountdown(config);
return <div>{countdown.timeDisplay.formatted}</div>;
}Custom Time Formatting
import { CountdownWidget } from 'repeating-countdown';
function CustomFormattedCountdown() {
const formatTime = (time) => {
if (time.days > 0) {
return `${time.days} days, ${time.hours}h ${time.minutes}m`;
}
return `${time.hours}:${time.minutes.toString().padStart(2, '0')}:${time.seconds.toString().padStart(2, '0')}`;
};
return (
<CountdownWidget
config={{ duration: 1000 * 60 * 60 }}
formatTime={formatTime}
/>
);
}Manual Reset Control
import { useRepeatingCountdown } from 'repeating-countdown';
function ManualResetCountdown() {
const countdown = useRepeatingCountdown({
duration: 1000 * 60 * 30, // 30 minutes
autoReset: false,
onComplete: () => {
// Show notification or trigger action
alert('Time\'s up!');
}
});
return (
<div>
<h2>{countdown.timeDisplay.formatted}</h2>
<div>Status: {countdown.isCompleted ? 'Completed' : countdown.isPaused ? 'Paused' : 'Running'}</div>
{!countdown.isCompleted && (
<button onClick={countdown.isPaused ? countdown.resume : countdown.pause}>
{countdown.isPaused ? 'Start' : 'Pause'}
</button>
)}
<button onClick={countdown.reset}>Reset</button>
</div>
);
}Multiple Countdowns
import { useRepeatingCountdown } from 'repeating-countdown';
function MultipleCountdowns() {
const workTimer = useRepeatingCountdown({
duration: 1000 * 60 * 25, // 25 minutes (Pomodoro)
autoReset: true
});
const breakTimer = useRepeatingCountdown({
duration: 1000 * 60 * 5, // 5 minutes
autoReset: true
});
return (
<div>
<div>
<h3>Work Timer</h3>
<div>{workTimer.timeDisplay.formatted}</div>
<button onClick={workTimer.isPaused ? workTimer.resume : workTimer.pause}>
{workTimer.isPaused ? 'Start' : 'Pause'}
</button>
</div>
<div>
<h3>Break Timer</h3>
<div>{breakTimer.timeDisplay.formatted}</div>
<button onClick={breakTimer.isPaused ? breakTimer.resume : breakTimer.pause}>
{breakTimer.isPaused ? 'Start' : 'Pause'}
</button>
</div>
</div>
);
}Utility Functions
The package also exports utility functions for custom implementations:
import {
calculateNextResetTime,
calculateTimeRemaining,
formatTimeRemaining,
formatTimeString,
calculateProgress,
shouldAutoReset,
createDefaultConfig,
validateConfig,
getCurrentTime
} from 'repeating-countdown';
// Calculate next reset time
const nextReset = calculateNextResetTime(
1000 * 60 * 60, // 1 hour
-300, // EST timezone
5000 // 5 seconds server offset
);
// Format time remaining
const timeLeft = 1000 * 60 * 30; // 30 minutes
const formatted = formatTimeRemaining(timeLeft);
console.log(formatted.formatted); // "30m 00s"
// Validate configuration
const config = { duration: 1000 * 60 * 60 };
const errors = validateConfig(config);
if (errors.length > 0) {
console.error('Invalid config:', errors);
}Styling
The CountdownWidget component comes with built-in styles but can be customized:
.repeating-countdown-widget {
/* Custom styles */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.repeating-countdown-widget button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Changelog
1.0.0
- Initial release
- Core countdown functionality
- React hook and widget component
- Timezone and server sync support
- TypeScript definitions
- Comprehensive test suite
