DEV Community

Mohamud Dahir Abdi
Mohamud Dahir Abdi

Posted on

Build a Sleek Calculator with Dark Mode - Interactive Guide

Let's create a modern calculator that's both beautiful and functional, with all the code explained in an engaging way. By the end, you'll have a calculator that works on all devices and even supports keyboard input!

🎨 The Design Vision

We're building a calculator with:

  • A dark theme (with easy light mode potential)
  • Full calculation history
  • Keyboard support (type directly!)
  • Responsive design (works on phones too)
  • Smooth animations

Calculator Preview


🛠️ Let's Build It!

1. The HTML Foundation

Our calculator needs:

  • A display area (for current input and history)
  • Number buttons (0-9)
  • Operator buttons (+, -, *, /)
  • Special functions (AC, DEL, %)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Neon Calculator</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="calculator">
        <!-- Display Area -->
        <div class="display">
            <div class="history"></div>
            <input type="text" id="output" readonly>
        </div>

        <!-- Buttons Grid -->
        <div class="buttons">
            <button data-value="AC" class="ac">AC</button>
            <button data-value="DEL" class="del">DEL</button>
            <button data-value="%" class="operator">%</button>
            <button data-value="/" class="operator">÷</button>

            <button data-value="7" class="number">7</button>
            <button data-value="8" class="number">8</button>
            <button data-value="9" class="number">9</button>
            <button data-value="*" class="operator">×</button>

            <button data-value="4" class="number">4</button>
            <button data-value="5" class="number">5</button>
            <button data-value="6" class="number">6</button>
            <button data-value="-" class="operator"></button>

            <button data-value="1" class="number">1</button>
            <button data-value="2" class="number">2</button>
            <button data-value="3" class="number">3</button>
            <button data-value="+" class="operator">+</button>

            <button data-value="0" class="number zero">0</button>
            <button data-value="." class="number">.</button>
            <button data-value="=" class="equals">=</button>
        </div>
    </div>

    <script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • data-value attributes store what each button does
  • Special classes like operator and number help with styling
  • The zero button is wider (we'll style it that way)

2. Stylish CSS Makeover

Let's give our calculator some personality with:

  • A sleek dark theme
  • Glowing operator buttons
  • Smooth button presses
:root {
    --bg-color: #1e1e2e;
    --display-bg: #2a2a3a;
    --button-bg: #3a3a4a;
    --operator-color: #ff9500;
    --equals-color: #ff2d75;
    --ac-del-color: #a5a5a5;
    --text-color: #ffffff;
}

body {
    background: var(--bg-color);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    font-family: 'Segoe UI', sans-serif;
    transition: all 0.3s ease;
}

.calculator {
    width: 320px;
    background: var(--bg-color);
    border-radius: 20px;
    padding: 20px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

.display {
    background: var(--display-bg);
    border-radius: 10px;
    padding: 20px;
    margin-bottom: 20px;
    text-align: right;
}

.history {
    color: rgba(255, 255, 255, 0.5);
    height: 20px;
    font-size: 14px;
}

#output {
    width: 100%;
    border: none;
    background: transparent;
    color: var(--text-color);
    font-size: 36px;
    text-align: right;
    outline: none;
}

.buttons {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}

button {
    height: 60px;
    border: none;
    border-radius: 10px;
    font-size: 24px;
    cursor: pointer;
    transition: all 0.1s;
    color: var(--text-color);
    background: var(--button-bg);
}

button:active {
    transform: scale(0.95);
}

.number {
    background: var(--button-bg);
}

.operator {
    background: var(--operator-color);
}

.equals {
    background: var(--equals-color);
}

.ac, .del {
    background: var(--ac-del-color);
}

.zero {
    grid-column: span 2;
}

/* Glow effect on hover */
.operator:hover, .equals:hover {
    filter: brightness(1.2);
    box-shadow: 0 0 10px currentColor;
}
Enter fullscreen mode Exit fullscreen mode

Design Highlights:

  • CSS variables make theme changes easy
  • Grid layout for perfect button alignment
  • Interactive button effects (press and glow)
  • The zero button spans two columns

3. JavaScript Magic

Now for the brains! Our calculator needs to:

  • Handle button clicks
  • Manage calculations
  • Support keyboard input
  • Show history
const output = document.getElementById('output');
const buttons = document.querySelectorAll('button');
const historyDisplay = document.querySelector('.history');

let currentInput = '0';
let calculationHistory = '';

// Initialize display
output.value = currentInput;

// Update the calculator display
function updateDisplay() {
    output.value = currentInput;

    // Adjust font size for long numbers
    output.style.fontSize = currentInput.length > 12 ? '24px' : '36px';
}

// Check if input is valid
function isValidInput(value) {
    // Prevent multiple decimals
    if (value === '.' && currentInput.includes('.') && !'+-*/'.includes(currentInput.slice(-1))) {
        return false;
    }

    // Prevent consecutive operators
    if ('+-*/'.includes(value) && '+-*/'.includes(currentInput.slice(-1))) {
        return false;
    }

    return true;
}

// Perform the calculation
function calculate() {
    try {
        // Replace × and ÷ with * and /
        let expression = currentInput.replace(/×/g, '*').replace(/÷/g, '/');

        // Use Function constructor instead of eval
        const result = new Function(`return ${expression}`)();

        // Format the result
        return Number.isInteger(result) ? result.toString() : result.toFixed(4);
    } catch {
        return 'Error';
    }
}

// Handle button clicks
buttons.forEach(button => {
    button.addEventListener('click', () => {
        const value = button.dataset.value;

        if (value === 'AC') {
            // Clear everything
            currentInput = '0';
            calculationHistory = '';
            historyDisplay.textContent = '';
        } else if (value === 'DEL') {
            // Backspace functionality
            currentInput = currentInput.length > 1 ? currentInput.slice(0, -1) : '0';
        } else if (value === '=') {
            // Calculate and show history
            calculationHistory = currentInput;
            historyDisplay.textContent = calculationHistory + ' =';
            currentInput = calculate();
        } else {
            // Add numbers or operators
            if (!isValidInput(value)) return;

            if (currentInput === '0' && !'+-*/'.includes(value)) {
                currentInput = value;
            } else {
                currentInput += value;
            }
        }

        updateDisplay();
    });
});

// Keyboard support
document.addEventListener('keydown', (e) => {
    const keyMap = {
        'Enter': '=',
        'Backspace': 'DEL',
        'Escape': 'AC',
        '*': '*',
        '+': '+',
        '-': '-',
        '/': '/',
        '%': '%',
        '.': '.'
    };

    if (keyMap[e.key]) {
        document.querySelector(`button[data-value="${keyMap[e.key]}"]`).click();
    } else if (!isNaN(e.key) || e.key === '0') {
        document.querySelector(`button[data-value="${e.key}"]`).click();
    }
});
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • Safe calculations using Function instead of eval
  • Input validation prevents errors
  • Keyboard support for quick typing
  • History tracking shows your previous calculation
  • Error handling for invalid expressions

🚀 Taking It Further

Want to enhance your calculator? Try these ideas:

  1. Add Light/Dark Mode Toggle
const themeToggle = document.createElement('button');
themeToggle.textContent = '🌙';
document.body.prepend(themeToggle);

themeToggle.addEventListener('click', () => {
    document.body.classList.toggle('light-mode');
});
Enter fullscreen mode Exit fullscreen mode

Add to CSS:

.light-mode {
    --bg-color: #f0f2f5;
    --display-bg: #ffffff;
    --button-bg: #e0e0e0;
    --text-color: #000000;
}
Enter fullscreen mode Exit fullscreen mode
  1. Add Scientific Functions
<button data-value="Math.sqrt("></button>
<button data-value="Math.pow(,2)"></button>
Enter fullscreen mode Exit fullscreen mode
  1. Add Memory Functions
let memory = 0;

function memoryAdd() {
    memory += parseFloat(currentInput);
}
Enter fullscreen mode Exit fullscreen mode

💡 Why This Calculator Rocks

  • No eval() - Safer calculations using Function constructor
  • Great UX - Visual feedback on button presses
  • Responsive - Works on any device
  • Accessible - Works with keyboard and screen readers
  • Easy to Extend - Add more features easily

Now you've got a calculator that looks great and works even better! What feature will you add next? Maybe voice control or calculation graphs? The possibilities are endless!

Top comments (0)