Digital & Analog Dual Clock

A dynamic dual-mode clock with synchronized analog ticking hands, 12h/24h digital time, date formatting, and light/dark theme switch.

Difficulty: Beginner Est. Time: 20 mins Vanilla JS (ES6+) Includes HTML, CSS, JS & README (.ZIP)
Live UI Runner

Digital & Analog Dual Clock

live-sandbox://digital-analog-clock

1. Project Overview & Features

The Digital & Analog Dual Clock is an essential frontend project designed to help you bridge the gap between learning JavaScript syntax and building interactive, responsive web applications.

Key Features Implemented:

  • Analog clock face with hour, minute, and continuous sweeping second hand
  • Digital clock with seconds, AM/PM tag, and 12h / 24h toggle
  • Full date banner with Day of Week, Month, Day, and Year
  • Dark and Light theme toggle with state retention

2. Step-by-Step Code Walkthrough

A Step 1: Semantic HTML Structure

We structure the interface using clean, semantic HTML elements. This ensures maximum accessibility and provides intuitive hooks for CSS classes and JavaScript query selectors.

HTML (index.html)
<div class="clock-app" id="clock-app">
  <div class="app-top-bar">
    <button id="theme-toggle" class="control-btn" title="Toggle Theme">
      <i class="fas fa-moon"></i>
    </button>
    <button id="format-toggle" class="control-btn" title="Toggle 12/24 Hour">
      <span id="format-label">12H</span>
    </button>
  </div>

  <div class="analog-clock">
    <div class="clock-face">
      <!-- 12 hour tick marks -->
      <span class="number number-12">12</span>
      <span class="number number-3">3</span>
      <span class="number number-6">6</span>
      <span class="number number-9">9</span>
      
      <div class="hand hour-hand" id="hour-hand"></div>
      <div class="hand minute-hand" id="min-hand"></div>
      <div class="hand second-hand" id="sec-hand"></div>
      <div class="center-dot"></div>
    </div>
  </div>

  <div class="digital-section">
    <div class="digital-time">
      <span id="dig-hours">00</span>:<span id="dig-minutes">00</span>:<span id="dig-seconds">00</span>
      <span id="dig-ampm" class="ampm-tag">AM</span>
    </div>
    <div id="full-date" class="full-date">Monday, January 1, 2026</div>
  </div>
</div>

B Step 2: Styling & Responsive CSS

Modern CSS flexbox and grid layouts are used to make the UI look polished, centered, and responsive across desktop, tablet, and mobile screens.

CSS (style.css)
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
body {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0f172a;
  color: #f8fafc;
  padding: 20px;
  transition: background 0.3s;
}
body.light-theme {
  background: #f1f5f9;
  color: #0f172a;
}
.clock-app {
  background: #1e293b;
  border-radius: 24px;
  padding: 28px;
  width: 100%;
  max-width: 380px;
  border: 1px solid #334155;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: all 0.3s;
}
body.light-theme .clock-app {
  background: #ffffff;
  border-color: #e2e8f0;
  box-shadow: 0 15px 35px rgba(0, 0, 0, 0.08);
}
.app-top-bar {
  display: flex;
  justify-content: space-between;
  width: 100%;
  margin-bottom: 20px;
}
.control-btn {
  background: #334155;
  border: none;
  color: #94a3b8;
  padding: 8px 14px;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.85rem;
  transition: all 0.2s;
}
body.light-theme .control-btn {
  background: #f1f5f9;
  color: #475569;
}
.control-btn:hover {
  background: #8b5cf6;
  color: #ffffff;
}
.analog-clock {
  width: 220px;
  height: 220px;
  border-radius: 50%;
  background: #0f172a;
  border: 8px solid #334155;
  position: relative;
  box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.5), 0 8px 20px rgba(0, 0, 0, 0.2);
  margin-bottom: 24px;
}
body.light-theme .analog-clock {
  background: #f8fafc;
  border-color: #e2e8f0;
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05), 0 8px 20px rgba(0, 0, 0, 0.06);
}
.clock-face {
  position: relative;
  width: 100%;
  height: 100%;
}
.number {
  position: absolute;
  color: #94a3b8;
  font-weight: 700;
  font-size: 0.95rem;
}
.number-12 { top: 8px; left: 50%; transform: translateX(-50%); }
.number-3 { right: 10px; top: 50%; transform: translateY(-50%); }
.number-6 { bottom: 8px; left: 50%; transform: translateX(-50%); }
.number-9 { left: 10px; top: 50%; transform: translateY(-50%); }

.hand {
  position: absolute;
  bottom: 50%;
  left: 50%;
  transform-origin: bottom center;
  border-radius: 6px;
  transition: transform 0.05s cubic-bezier(0.4, 2.08, 0.55, 0.44);
}
.hour-hand {
  width: 6px;
  height: 55px;
  background: #8b5cf6;
  margin-left: -3px;
  z-index: 3;
}
.minute-hand {
  width: 4px;
  height: 75px;
  background: #38bdf8;
  margin-left: -2px;
  z-index: 4;
}
.second-hand {
  width: 2px;
  height: 85px;
  background: #ef4444;
  margin-left: -1px;
  z-index: 5;
}
.center-dot {
  width: 12px;
  height: 12px;
  background: #f8fafc;
  border: 3px solid #8b5cf6;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 6;
}
.digital-section {
  text-align: center;
}
.digital-time {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 1px;
  color: #f8fafc;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
}
body.light-theme .digital-time {
  color: #0f172a;
}
.ampm-tag {
  font-size: 0.85rem;
  color: #8b5cf6;
  font-weight: 700;
  text-transform: uppercase;
}
.full-date {
  color: #94a3b8;
  font-size: 0.88rem;
  margin-top: 6px;
  font-weight: 500;
}
body.light-theme .full-date {
  color: #64748b;
}

C Step 3: JavaScript Logic & Event Handling

Here is the complete JavaScript code handling the state, event listeners, mathematical logic, and dynamic DOM rendering:

JavaScript (script.js)
let is24Hour = false;
let isDark = true;

const hourHand = document.getElementById('hour-hand');
const minHand = document.getElementById('min-hand');
const secHand = document.getElementById('sec-hand');

const digHours = document.getElementById('dig-hours');
const digMinutes = document.getElementById('dig-minutes');
const digSeconds = document.getElementById('dig-seconds');
const digAmpm = document.getElementById('dig-ampm');
const fullDate = document.getElementById('full-date');

const themeBtn = document.getElementById('theme-toggle');
const formatBtn = document.getElementById('format-toggle');
const formatLabel = document.getElementById('format-label');

function updateClock() {
  const now = new Date();

  const seconds = now.getSeconds();
  const minutes = now.getMinutes();
  const hours = now.getHours();

  // Analog hands angles
  const secDeg = (seconds / 60) * 360;
  const minDeg = ((minutes + seconds / 60) / 60) * 360;
  const hourDeg = (((hours % 12) + minutes / 60) / 12) * 360;

  secHand.style.transform = `rotate(${secDeg}deg)`;
  minHand.style.transform = `rotate(${minDeg}deg)`;
  hourHand.style.transform = `rotate(${hourDeg}deg)`;

  // Digital Time
  let displayHours = hours;
  let ampm = '';

  if (!is24Hour) {
    ampm = hours >= 12 ? 'PM' : 'AM';
    displayHours = hours % 12 || 12;
    digAmpm.style.display = 'inline';
    digAmpm.textContent = ampm;
  } else {
    digAmpm.style.display = 'none';
  }

  digHours.textContent = String(displayHours).padStart(2, '0');
  digMinutes.textContent = String(minutes).padStart(2, '0');
  digSeconds.textContent = String(seconds).padStart(2, '0');

  // Full date
  const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
  fullDate.textContent = now.toLocaleDateString('en-US', options);
}

// Format toggle
formatBtn.addEventListener('click', () => {
  is24Hour = !is24Hour;
  formatLabel.textContent = is24Hour ? '24H' : '12H';
  updateClock();
});

// Theme toggle
themeBtn.addEventListener('click', () => {
  isDark = !isDark;
  document.body.classList.toggle('light-theme', !isDark);
  themeBtn.innerHTML = isDark ? '<i class="fas fa-moon"></i>' : '<i class="fas fa-sun"></i>';
});

// Run every second
setInterval(updateClock, 1000);
updateClock();

3. Core JavaScript Concepts You Learned

setInterval & requestAnimationFrame

Crucial concept utilized to power the dynamic state, user interactions, and styling of this project.

Date Object Methods

Crucial concept utilized to power the dynamic state, user interactions, and styling of this project.

CSS transform: rotate()

Crucial concept utilized to power the dynamic state, user interactions, and styling of this project.

Trigonometric Angles

Crucial concept utilized to power the dynamic state, user interactions, and styling of this project.

Theme Switching

Crucial concept utilized to power the dynamic state, user interactions, and styling of this project.

4. How to Run Locally on Your Computer

  1. Download the project ZIP: Click the Download Project (.ZIP) button at the top or in the live runner to save digital-analog-clock-project.zip.
  2. Extract the archive: Unzip the downloaded file. Inside you will find separate index.html, style.css, script.js, index-standalone.html, and a comprehensive README.md.
  3. Open in any browser: Simply double-click index.html (or index-standalone.html) to open and test immediately in Chrome, Firefox, Safari, or Edge.
  4. Edit in Visual Studio Code: Open the extracted folder in VS Code. Right-click index.html and select "Open with Live Server" to enjoy instant live reloading as you modify HTML, CSS, or JS!

Bonus Challenges for Learners

Ready to level up? Try adding these extra features on your own:

  • Add sound effects or audio feedback for user button clicks.
  • Add custom theme color customizer with CSS variables.
  • Export the results to PDF or copy as a formatted text summary.

Other Beginner Projects You Might Like

Intermediate30 mins
Timers & Clocks

3D Precision Stopwatch & Chronograph

An ultra-modern 3D interactive stopwatch and chronograph with real-time 3D gyroscope tilt, sweeping second hand, dual sub-dials, tactile mechanical pushers, theme switcher, and lap split telemetry.

3D CSS Perspective & TiltrequestAnimationFrame TimingWeb Audio API Haptics+2