Modern JavaScript/TypeScript Clock Library - API Reference & Usage Guide
// Import the createClock function
import { createClock } from 'new-js-clock';
// Create a clock
const clock = createClock(document.getElementById('clock'));
// Import with full TypeScript support
import { createClock, ClockOptions, ClockInstance } from 'new-js-clock';
// Create a clock with type safety
const clock: ClockInstance = createClock(
document.getElementById('clock')!
);
// Or use the full options interface
const options: ClockOptions = {
showCenti: true,
countdown: false
};
const precisionClock = createClock(
document.getElementById('precision')!,
'10:30:45',
options
);
// CommonJS support
const { createClock } = require('new-js-clock');
const clock = createClock(document.getElementById('clock'));
For direct browser usage without a bundler:
<!-- Minified (recommended for production) -->
<script src="https://unpkg.com/new-js-clock/dist/new-js-clock.min.js"></script>
<!-- Or via jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/new-js-clock/dist/new-js-clock.min.js"></script>
<!-- Unminified (for debugging) -->
<script src="https://unpkg.com/new-js-clock/dist/new-js-clock.js"></script>
<script>
// Library is available as global NewJSClock
var clock = NewJSClock.createClock(document.getElementById('clock'));
// All features work the same
var countdown = NewJSClock.createClock(
document.getElementById('timer'),
'00:05:00',
{ countdown: true }
);
</script>
# Clone the repository
git clone https://github.com/thiago-cavalcanti/new-js-clock.git
cd New-JS-Clock
# Install dependencies
pnpm install
# Build (includes TypeScript type checking)
pnpm run build
# Run tests
pnpm test
# Run linting
pnpm lint
Creates a new clock instance attached to a DOM element.
createClock(element: HTMLElement, initialTime?: string, options?: ClockOptions): ClockInstance
| Parameter | Type | Required | Description |
|---|---|---|---|
element |
HTMLElement | Required | The DOM element where the clock will be rendered |
initialTime |
string | Optional | Start time in "HH:MM:SS" or "HH:MM:SS:CC" format. If omitted, uses system time. |
options |
ClockOptions | Optional | Configuration options object |
| Property | Type | Default | Description |
|---|---|---|---|
showCenti |
boolean | false |
Display centiseconds (hundredths of a second) |
countdown |
boolean | false |
Run as countdown timer instead of counting up |
showHour |
boolean | true |
Show hours in the display |
showMinute |
boolean | true |
Show minutes in the display |
callback |
function | undefined |
Called when countdown reaches zero |
use12Hour |
boolean | false |
Use 12-hour format with AM/PM indicator |
timezoneOffset |
number | undefined |
Static timezone offset in hours from UTC (e.g., -5 for EST, +1 for CET, +5.5 for IST). Does NOT handle DST. |
timezone |
string | undefined |
IANA timezone name for DST-aware timezone support (e.g., "America/New_York", "Europe/London"). Automatically handles daylight saving time. |
stopwatch |
boolean | false |
Run as stopwatch (counts up from 00:00:00) instead of using system time |
lap |
boolean | false |
Enable lap/split mode - records lap times. Requires stopwatch to be enabled. |
lapMode |
"splits" | "laps" | "both" | "both" |
Type of lap recording: "splits" (cumulative time since start), "laps" (time between laps), or "both" |
lapWord |
string | "Split" in lapMode: "splits", otherwise "Lap" |
Custom word to display before lap number (e.g., "Split", "Lap"). Set to "" for no word. |
useAnimationFrame |
boolean | false |
Use requestAnimationFrame for smoother updates. Automatically falls back to setTimeout when the page is hidden (background tab). |
timezone with IANA names for DST-aware clocks. Use timezoneOffset only when you need a fixed offset that never changes.
timezoneOffset parameter expects the absolute UTC offset for the target timezone, not a relative offset from local time. Pass the target timezone's UTC offset directly (e.g., -5 for EST/UTC-5, 0 for GMT/UTC+0, 9 for JST/UTC+9). Do not calculate relative offsets from your local timezone.
timezone parameter accepts IANA timezone identifiers (e.g., "America/New_York", "Europe/Paris", "Asia/Tokyo"). The browser's Intl API handles DST transitions automatically. You cannot use both timezone and timezoneOffset simultaneously.
initialTime), the clock derives display values from Date/Intl on every update tick for wall-clock accuracy. Increment/decrement ticking is used for countdown and stopwatch/custom-time modes.
requestAnimationFrame for smoother visual updates synced to your display's refresh rate (60/120/144Hz). When the page is hidden (background tab), it automatically falls back to setTimeout to ensure the clock stays accurate. This is ideal for stopwatches and visual timers where smoothness matters, while still maintaining accuracy when the user switches tabs.
The createClock function returns an object with the following methods:
| Method | Returns | Description |
|---|---|---|
getTime() |
string | Returns the current time as a formatted string (e.g., "14:30:25" or "14:30:25:50") |
setTime(timeString) |
void | Sets a new time for the clock without destroying the instance. Accepts "HH:MM:SS" or "HH:MM:SS:CC" format. |
startClock() |
void | Starts or resumes the clock if it was stopped |
stopClock() |
void | Pauses the clock |
toggleClock() |
void | Toggles between running and stopped states |
isRunning() |
boolean | Returns true if the clock is currently running |
reset() |
void | Resets the clock to its initial time and restarts it. Perfect for countdown timers! |
lap() |
string | Records a lap/split time and returns it as a string. Only works when lap option is enabled. |
getLaps() |
string[] | Returns an array of all recorded lap/split times based on lapMode. Only works when lap is enabled. |
getSplitTimes() |
string[] | Returns an array of split times (cumulative). Only works when lap is enabled with lapMode "splits" or "both". |
getLapTimes() |
string[] | Returns an array of lap times (time between laps). Only works when lap is enabled with lapMode "laps" or "both". |
getLapRecords() |
LapRecord[] | Returns an array of lap records with full details (lapNumber, lapTime, splitTime, preciseElapsedMs, timestamp). Only works when lap is enabled. |
clearLaps() |
void | Clears all recorded lap/split times. Only works when lap is enabled. |
bestLap() |
LapRecord | null | Returns the lap record with the fastest lap time. Only works when lap is enabled with lapMode "laps" or "both". |
worstLap() |
LapRecord | null | Returns the lap record with the slowest lap time. Only works when lap is enabled with lapMode "laps" or "both". |
destroy() |
void | Cleans up the clock instance, stops the timer, and clears the element |
createClock operates independently of others.
The LapRecord interface contains detailed information about each recorded lap:
| Property | Type | Description |
|---|---|---|
lapNumber |
number | The sequential lap number (1, 2, 3, ...) |
lapTime |
string | The lap time (time since last lap) in "HH:MM:SS" or "HH:MM:SS:CC" format |
splitTime |
string | The split time (cumulative time since start) in "HH:MM:SS" or "HH:MM:SS:CC" format |
preciseElapsedMs |
number | High-resolution lap delta in milliseconds (from performance.now()), enabling sub-millisecond precision for lap comparisons |
timestamp |
number | Unix timestamp (milliseconds) when the lap was recorded |
Display the current system time:
import { createClock } from 'new-js-clock';
const clock = createClock(document.getElementById('clock'));
// The clock automatically starts and syncs with system time
// Display: "14:30:25" (updates every second)
Show centiseconds for higher precision:
const clock = createClock(
document.getElementById('precision-clock'),
undefined,
{ showCenti: true }
);
// Display: "14:30:25:83" (updates every 10ms)
Create a countdown with a callback:
const countdown = createClock(
document.getElementById('timer'),
'00:05:00', // 5 minutes
{
countdown: true,
callback: () => {
alert('Time is up!');
// Or play a sound, redirect, etc.
}
}
);
// Control the countdown
countdown.stopClock(); // Pause
countdown.startClock(); // Resume
countdown.toggleClock(); // Toggle
Start from a specific time and count up:
const custom = createClock(
document.getElementById('custom'),
'10:30:45' // Start at this time
);
// Counts up from 10:30:45
// Will roll over at 23:59:59 to 00:00:00
Create multiple clocks that work independently:
// Clock 1: System time
const clock1 = createClock(document.getElementById('clock1'));
// Clock 2: Countdown from 10 minutes
const clock2 = createClock(
document.getElementById('clock2'),
'00:10:00',
{ countdown: true }
);
// Clock 3: Custom time with centiseconds
const clock3 = createClock(
document.getElementById('clock3'),
'05:00:00',
{ showCenti: true }
);
// Each clock operates independently!
clock1.stopClock(); // Only stops clock1
clock2.stopClock(); // Only stops clock2
Display time in 12-hour format with AM/PM indicator:
const clock12h = createClock(
document.getElementById('clock12h'),
undefined, // Uses system time
{ use12Hour: true }
);
// Display examples:
// "02:30:45 PM" for 14:30:45
// "12:00:00 AM" for midnight
// "12:00:00 PM" for noon
const clock12h: ClockInstance = createClock(
document.getElementById('clock12h')!,
undefined, // Uses system time
{ use12Hour: true }
);
// Works with all other options:
const clock12hWithCenti: ClockInstance = createClock(
document.getElementById('clock12h-centi')!,
undefined,
{
use12Hour: true,
showCenti: true
}
);
// Display: "02:30:45:50 PM"
Display times from different timezones - choose between DST-aware (recommended) or static offset:
// Using IANA timezone names (DST-aware)
// New York - automatically adjusts for DST
const nyClock = createClock(
document.getElementById('ny-time'),
undefined,
{ timezone: 'America/New_York' }
);
// London - automatically adjusts for BST
const londonClock = createClock(
document.getElementById('london-time'),
undefined,
{ timezone: 'Europe/London' }
);
// Tokyo - no DST, but still works
const tokyoClock = createClock(
document.getElementById('tokyo-time'),
undefined,
{ timezone: 'Asia/Tokyo' }
);
// Sydney - Southern Hemisphere DST
const sydneyClock = createClock(
document.getElementById('sydney-time'),
undefined,
{ timezone: 'Australia/Sydney' }
);
// Combine with 12-hour format
const ny12hClock = createClock(
document.getElementById('ny-12h'),
undefined,
{
timezone: 'America/New_York',
use12Hour: true
}
);
// Using static offset (does NOT handle DST)
// New York (EST): UTC-5 - stays at -5 even during EDT
const nyClock = createClock(
document.getElementById('ny-time'),
undefined,
{ timezoneOffset: -5 }
);
// London (GMT): UTC+0
const londonClock = createClock(
document.getElementById('london-time'),
undefined,
{ timezoneOffset: 0 }
);
// Tokyo (JST): UTC+9
const tokyoClock = createClock(
document.getElementById('tokyo-time'),
undefined,
{ timezoneOffset: 9 }
);
// Mumbai (IST): UTC+5:30
const mumbaiClock = createClock(
document.getElementById('mumbai-time'),
undefined,
{ timezoneOffset: 5.5 }
);
America/New_York, America/Los_Angeles, Europe/London, Europe/Paris, Asia/Tokyo, Asia/Shanghai, Australia/Sydney, Pacific/Auckland. See the full list of IANA timezones.
A practical example - Pomodoro technique timer:
let pomodoroCount = 0;
const pomodoro = createClock(
document.getElementById('pomodoro'),
'00:25:00',
{
countdown: true,
callback: () => {
pomodoroCount++;
alert(`Pomodoro ${pomodoroCount} completed! Take a 5-minute break.`);
// Reset for next pomodoro
pomodoro.destroy();
pomodoro = createClock(
document.getElementById('pomodoro'),
'00:25:00',
{
countdown: true,
callback: () => alert('Next pomodoro done!')
}
);
}
}
);
Hide hours for a simple minute:second display:
const kitchenTimer = createClock(
document.getElementById('kitchen'),
'00:03:00',
{
countdown: true,
showHour: false, // Hides hours
callback: () => {
document.getElementById('kitchen').style.background = '#ffebee';
alert('Dinner is ready!');
}
}
);
// Display: "03:00" instead of "00:03:00"
Create a simple stopwatch with lap functionality:
const stopwatch = createClock(
document.getElementById('stopwatch'),
'00:00:00',
{ showCenti: true }
);
const laps = [];
function recordLap() {
const lapTime = stopwatch.getTime();
laps.push(lapTime);
console.log(`Lap ${laps.length}: ${lapTime}`);
}
function resetStopwatch() {
stopwatch.reset(); // Uses the new reset() method!
laps.length = 0;
}
Create a countdown that can be easily restarted without recreating:
const countdown = createClock(
document.getElementById('countdown'),
'00:05:00',
{
countdown: true,
callback: () => {
alert('Time is up!');
}
}
);
// User can pause/resume
countdown.stopClock();
countdown.startClock();
// Reset to original time and restart - no need to destroy/recreate!
countdown.reset();
// This is much cleaner than the old way:
// countdown.destroy();
// countdown = createClock(element, '00:05:00', {...});
reset() method is perfect for countdown timers that users may want to restart. It resets to the initial time and automatically starts running again.
Change the displayed time dynamically without destroying the clock:
const clock = createClock(
document.getElementById('clock'),
'10:00:00'
);
// Later, change to a different time
clock.setTime('15:30:00');
// Works with centiseconds too
const precision = createClock(
document.getElementById('precision'),
'00:00:00:00',
{ showCenti: true }
);
clock.setTime('01:23:45:67');
// Perfect for setting a countdown time from user input
const userInput = document.getElementById('time-input').value; // e.g., "00:10:00"
countdown.setTime(userInput);
setTime() validates the time string and throws an error if invalid. Wrap in try-catch for user input.
A practical Pomodoro timer using the new reset() method:
let pomodoroCount = 0;
const POMODORO_TIME = '00:25:00';
const BREAK_TIME = '00:05:00';
let isBreak = false;
const pomodoro = createClock(
document.getElementById('pomodoro'),
POMODORO_TIME,
{
countdown: true,
callback: () => {
if (!isBreak) {
pomodoroCount++;
alert(`Pomodoro ${pomodoroCount} completed! Take a 5-minute break.`);
isBreak = true;
pomodoro.setTime(BREAK_TIME);
pomodoro.startClock();
} else {
alert('Break over! Starting next pomodoro.');
isBreak = false;
pomodoro.setTime(POMODORO_TIME);
pomodoro.startClock();
}
}
}
);
// Skip break button - just reset and continue
function skipBreak() {
isBreak = false;
pomodoro.setTime(POMODORO_TIME);
}
// Reset current pomodoro
function resetPomodoro() {
pomodoro.reset(); // Easy reset to initial time!
}
Create a stopwatch that counts up from 00:00:00:
const stopwatch = createClock(
document.getElementById('stopwatch'),
undefined,
{ stopwatch: true }
);
// Display starts at "00:00:00" and counts up
// Stopwatch runs indefinitely (doesn't stop at midnight)
// Control like any other clock
stopwatch.stopClock(); // Pause
stopwatch.startClock(); // Resume
stopwatch.toggleClock(); // Toggle
// Reset back to 00:00:00
stopwatch.reset();
Record lap times during a stopwatch run:
const stopwatch = createClock(
document.getElementById('stopwatch'),
undefined,
{
stopwatch: true,
lap: true, // Enable lap mode
lapWord: 'Split' // Custom word (default: "Split" in splits mode, otherwise "Lap")
}
);
// Record a lap - returns the lap time string
const lap1 = stopwatch.lap(); // "Split 1: 00:00:15"
const lap2 = stopwatch.lap(); // "Split 2: 00:00:32"
const lap3 = stopwatch.lap(); // "Split 3: 00:00:45"
// Get all laps as an array
const allLaps = stopwatch.getLaps();
// ["Split 1: 00:00:15", "Split 2: 00:00:32", "Split 3: 00:00:45"]
// Clear laps without stopping the stopwatch
stopwatch.clearLaps();
// Reset also clears laps
stopwatch.reset();
High-precision stopwatch for accurate timing:
const precisionStopwatch = createClock(
document.getElementById('precision-stopwatch'),
undefined,
{
stopwatch: true,
showCenti: true // Show centiseconds
}
);
// Display: "00:00:15:23" (hours:minutes:seconds:centiseconds)
Customize the lap word for different use cases:
// No word at all (just number and time)
const timer1 = createClock(
document.getElementById('timer1'),
undefined,
{ stopwatch: true, lap: true, lapWord: '' }
);
// Lap: "1: 00:01:23"
// Custom word for different sports
const raceTimer = createClock(
document.getElementById('race'),
undefined,
{ stopwatch: true, lap: true, lapWord: 'Checkpoint' }
);
// Lap: "Checkpoint 1: 00:05:30"
// Old jQuery syntax
$('#clock').jsclock();
$('#clock').jsclock('10:30:45');
$('#clock').jsclock('00:05:00', { countdown: true });
// Control methods (BROKEN for multiple clocks)
$.fn.jsclock.stopClock();
$.fn.jsclock.getTime();
// New ES module syntax
import { createClock } from 'new-js-clock';
const clock = createClock(document.getElementById('clock'));
const clock2 = createClock(document.getElementById('clock2'), '10:30:45');
const timer = createClock(
document.getElementById('timer'),
'00:05:00',
{ countdown: true }
);
// Control methods (WORKS correctly for each instance!)
clock.stopClock();
clock.getTime();
timer.startClock();
// New ES module syntax with TypeScript
import { createClock, ClockOptions, ClockInstance } from 'new-js-clock';
// Type-safe clock instances
const clock: ClockInstance = createClock(
document.getElementById('clock')!
);
const clock2 = createClock(
document.getElementById('clock2')!,
'10:30:45'
);
// Typed options
const timerOptions: ClockOptions = {
countdown: true,
callback: () => console.log('Time is up!')
};
const timer: ClockInstance = createClock(
document.getElementById('timer')!,
'00:05:00',
timerOptions
);
// All methods are type-safe
clock.stopClock();
const currentTime: string = clock.getTime();
const isRunning: boolean = timer.isRunning();
selenium/standalone-all-browsers on port 4444, running headless Chrome/Firefox/Edge for end-to-end behavior (including extended background-tab visibility scenarios)| Format | Example | Description |
|---|---|---|
HH:MM:SS |
"14:30:45" | Standard format (hours, minutes, seconds) |
HH:MM:SS:CC |
"14:30:45:50" | With centiseconds (hundredths of a second) |
showCenti is enabled but the initial time doesn't include centiseconds, they default to "00".
The library validates inputs and throws descriptive errors for invalid configurations. The caller is responsible for displaying error messages to users.
// TypeError: "Invalid countdown option: must be a boolean"
createClock(el, '10:30:45', { countdown: 'yes' });
// TypeError: "Invalid element: must be an HTMLElement"
createClock(undefined);
// TypeError: "Invalid options: must be an object"
createClock(el, undefined, 123);
createClock(el, undefined, []);
// Error: "Initial time required for countdown mode"
createClock(el, undefined, { countdown: true });
// Error: "Invalid time string format: must be HH:MM:SS or HH:MM:SS:CC with leading zeros"
createClock(el, '25:00:00'); // Hour > 23
createClock(el, '10:70:00'); // Minute > 59
createClock(el, '10:30'); // Missing seconds
// RangeError: "Invalid timezoneOffset: must be between -12 and +14"
createClock(el, undefined, { timezoneOffset: -13 }); // Too negative
createClock(el, undefined, { timezoneOffset: 15 }); // Too positive
// TypeError: "Invalid timezoneOffset option: must be a number"
createClock(el, undefined, { timezoneOffset: 'EST' }); // Wrong type
// RangeError: "Invalid timezone: "Invalid/Zone" is not a valid IANA timezone name"
createClock(el, undefined, { timezone: 'Invalid/Zone' });
// Error: "Cannot use both timezone and timezoneOffset options; choose one"
createClock(el, undefined, { timezone: 'America/New_York', timezoneOffset: -5 });
Always wrap clock creation in try-catch for production use:
try {
const clock = createClock(element, timeString, options);
} catch (error) {
// Display error to user (caller decides how)
element.textContent = error.message;
console.error('Failed to create clock:', error.message);
}
try {
const clock: ClockInstance = createClock(
document.getElementById('clock')!,
'10:30:45'
);
} catch (error: unknown) {
if (error instanceof Error) {
// Display error to user (caller decides how)
element.textContent = error.message;
console.error('Failed to create clock:', error.message);
}
}
TypeError for incorrect types, RangeError for out-of-range values, and Error for general validation failures.
New JS Clock 1.0.0 supports all modern browsers with native ES2020 support:
Requires ES2020+ support. For older browsers, use a transpiler like Babel.
The library has strong, behavior-focused test quality metrics:
selenium/standalone-all-browsers on port 4444, running headless Chrome/Firefox/Edge for end-to-end runtime behavior (including extended background-tab visibility scenarios)This library ships both ESM and CommonJS builds via package exports. Most bundlers work out of the box.
Works out of the box - no configuration needed.
// webpack.config.js
module.exports = {
resolve: {
extensions: ['.js', '.ts'],
conditionNames: ['import', 'require', 'default']
}
};
// esbuild.config.js
esbuild.build({
bundle: true,
format: 'esm',
mainFields: ['module', 'main']
});
// For CommonJS output
esbuild.build({
bundle: true,
format: 'cjs',
mainFields: ['main', 'module']
});
The library includes TypeScript declarations. For ESM projects, ensure your tsconfig.json uses a compatible moduleResolution:
{
"compilerOptions": {
"moduleResolution": "node" // or "node16", "nodenext", or "bundler"
}
}
moduleResolution: "bundler" in your project, the library will still work correctly since it's compiled with moduleResolution: "node" for broad compatibility. CommonJS projects can use require('new-js-clock').