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
🛠️ 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, %)
</span>
lang="en">
charset="UTF-8">
name="viewport" content="width=device-width, initial-scale=1.0">
Neon Calculator
rel="stylesheet" href="style.css">
class="calculator">
class="display">
class="history">
type="text" id="output" readonly>
class="buttons">
data-value="AC" class="ac">AC
data-value="DEL" class="del">DEL
data-value="%" class="operator">%
data-value="/" class="operator">÷
data-value="7" class="number">7
data-value="8" class="number">8
data-value="9" class="number">9
data-value="*" class="operator">×
data-value="4" class="number">4
data-value="5" class="number">5
data-value="6" class="number">6
data-value="-" class="operator">−
data-value="1" class="number">1
data-value="2" class="number">2
data-value="3" class="number">3
data-value="+" class="operator">+
data-value="0" class="number zero">0
data-value="." class="number">.
data-value="=" class="equals">=
<span class="na">src="script.js">
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:
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
Add Scientific Functions
data-value="Math.sqrt(">√
data-value="Math.pow(,2)">x²
Enter fullscreen mode
Exit fullscreen mode
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!