How to Build a BMI Calculator with HTML, CSS & JavaScript
Build a complete BMI calculator with HTML, CSS & JavaScript in this beginner tutorial — form handling, the BMI formula, validation, and colour-coded health categories.
Every developer remembers their first real project — the moment code stopped being abstract exercises and became something you could actually use. For thousands of beginners, that project is a calculator. But instead of building yet another basic arithmetic calculator, let us build something genuinely useful: a BMI (Body Mass Index) calculator with a clean interface, instant results, and health category feedback.
In this tutorial, you will build a complete BMI calculator using only HTML, CSS, and vanilla JavaScript — no frameworks, no libraries, no build tools. By the end, you will understand DOM manipulation, event handling, form validation, and how to turn a simple formula into a polished mini-app. The project takes about an hour, and the source code pattern you learn here applies to dozens of similar tools: age calculators, unit converters, loan estimators, and more.
What You'll Build (and What You'll Learn)
The finished app is a single-page tool: the user enters their height and weight, clicks a button (or the result updates live), and instantly sees their BMI value along with a category — Underweight, Normal, Overweight, or Obese — colour-coded for clarity. We will also add input validation so the app handles empty or silly inputs gracefully instead of crashing or showing NaN.
Along the way you will practise five core skills: structuring a page semantically with HTML, styling it into something you would proudly show someone with CSS, reading user input with JavaScript, performing the BMI calculation, and updating the page dynamically with the result. These five skills are the foundation of nearly all front-end development, which is why this small project punches far above its weight as a learning exercise.
Before we start, a quick note on the formula. BMI = weight in kilograms ÷ (height in metres)². So a person weighing 70 kg at 1.75 m tall has a BMI of 70 ÷ (1.75 × 1.75) = 70 ÷ 3.0625 ≈ 22.9 — squarely in the normal range. Our app will do exactly this math, then classify the result using the standard WHO categories.
Step 1: Setting Up the HTML Structure
Good HTML is semantic HTML — we use elements that describe what the content is, not just how it looks. Our page needs a heading, two labelled inputs (height in cm, weight in kg), a calculate button, and a result area. Here is the complete markup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BMI Calculator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="card">
<h1>BMI Calculator</h1>
<p class="subtitle">Check your Body Mass Index in seconds</p>
<label for="height">Height (cm)</label>
<input type="number" id="height" placeholder="e.g. 170" min="1">
<label for="weight">Weight (kg)</label>
<input type="number" id="weight" placeholder="e.g. 65" min="1">
<button id="calcBtn">Calculate BMI</button>
<div id="result" class="result hidden">
<span id="bmiValue">--</span>
<p id="bmiCategory"></p>
</div>
</main>
<script src="app.js"></script>
</body>
</html>
Notice a few deliberate choices. The type="number" inputs bring up numeric keyboards on mobile phones — a small UX win that costs nothing. Each input has a <label> linked via for/id, which is both an accessibility best practice and makes the label clickable. The result div starts with a hidden class so the page looks clean before the first calculation.
Step 2: Styling It with CSS
A calculator that looks like a 1998 tax form will not impress anyone, and styling is where beginners often give up too early. The good news: about 60 lines of modern CSS can make this app look genuinely professional. We will use a card layout centred on a soft gradient background, comfortable spacing, and a clear visual hierarchy.
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', system-ui, sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea, #764ba2);
padding: 20px;
}
.card {
background: #ffffff;
border-radius: 20px;
padding: 36px 32px;
width: 100%;
max-width: 400px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
}
.card h1 { font-size: 26px; margin-bottom: 4px; }
.subtitle { color: #777; margin-bottom: 24px; font-size: 14px; }
label { display: block; font-weight: 600; margin: 14px 0 6px; font-size: 14px; }
input {
width: 100%;
padding: 12px 14px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 16px;
}
input:focus { outline: none; border-color: #667eea; }
button {
width: 100%;
margin-top: 22px;
padding: 14px;
border: none;
border-radius: 10px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
font-size: 16px;
font-weight: 700;
cursor: pointer;
}
.result { text-align: center; margin-top: 24px; padding: 18px; border-radius: 12px; background: #f4f6ff; }
.result.hidden { display: none; }
#bmiValue { font-size: 44px; font-weight: 800; }
Two details worth appreciating: box-sizing: border-box makes padding behave intuitively (a classic beginner gotcha), and the flexbox centring on body keeps the card perfectly centred on any screen size.
Step 3: The JavaScript Logic — The BMI Formula
Now the brain of the app. Our script needs to: read both inputs when the button is clicked, validate them, convert height from centimetres to metres, apply the formula, classify the result, and display everything:
const heightInput = document.getElementById('height');
const weightInput = document.getElementById('weight');
const calcBtn = document.getElementById('calcBtn');
const resultBox = document.getElementById('result');
const bmiValue = document.getElementById('bmiValue');
const bmiCategory = document.getElementById('bmiCategory');
function getCategory(bmi) {
if (bmi < 18.5) return { label: 'Underweight', color: '#2196f3' };
if (bmi < 25) return { label: 'Normal weight', color: '#4caf50' };
if (bmi < 30) return { label: 'Overweight', color: '#ff9800' };
return { label: 'Obese', color: '#f44336' };
}
calcBtn.addEventListener('click', () => {
const heightCm = parseFloat(heightInput.value);
const weightKg = parseFloat(weightInput.value);
if (!heightCm || !weightKg || heightCm <= 0 || weightKg <= 0) {
alert('Please enter a valid height and weight.');
return;
}
const heightM = heightCm / 100;
const bmi = weightKg / (heightM * heightM);
const { label, color } = getCategory(bmi);
bmiValue.textContent = bmi.toFixed(1);
bmiValue.style.color = color;
bmiCategory.textContent = label;
bmiCategory.style.color = color;
resultBox.classList.remove('hidden');
});
Walk through the key lines. parseFloat converts the input strings to numbers; if the field is empty, it returns NaN, which is falsy — so !heightCm catches it. toFixed(1) rounds to one decimal place. Finally, we un-hide the result box and colour-code the output.
Step 4: Testing, Validation & Common Beginner Mistakes
Before calling any project "done", test it like a sceptic. Try these cases: normal values (170 cm, 65 kg → ~22.5, Normal), boundary values (a BMI of exactly 25 should show Overweight), empty fields (should show the alert, not NaN), zero or negative numbers (rejected).
Three mistakes trip up almost every beginner on this project. First, forgetting that input.value is always a string — arithmetic on strings concatenates instead of adding, which is why parseFloat matters. Second, dividing by height in centimetres instead of converting to metres first. Third, wiring the button with an inline onclick attribute instead of addEventListener.
Open your browser's developer console (F12) while testing. console.log(bmi) at each step is the fastest way to see what your code is actually doing versus what you assume it is doing.
Ideas to Take This Project Further
A finished tutorial project is a starting line, not a finish line. Here are five extensions, roughly ordered by difficulty: add a live-update mode that recalculates on every keystroke using the input event; support imperial units (feet/inches and pounds) with a unit toggle; draw a visual BMI scale with a marker showing where the user falls; save the last result in localStorage so it persists across visits; and add a small history log of past calculations with dates.
Each extension teaches something new — events, unit conversion logic, dynamic styling, browser storage, and array rendering respectively. And when you are ready for a slightly bigger challenge involving lists, filters, and persistent state, download the free source code of our Todo List App with localStorage — it is the natural next beginner project after this calculator.
Frequently Asked Questions
Q: Is BMI an accurate measure of health?
A: BMI is a useful screening tool but not a complete health picture — it does not distinguish muscle from fat, so athletes can score as "overweight" while being very fit. Treat it as a rough indicator, and consult a doctor for personal health decisions.
Q: Do I need any libraries or frameworks for this project?
A: No. The entire app is vanilla HTML, CSS, and JavaScript in three small files. That is deliberate: learning the fundamentals without framework magic makes every framework easier to learn later.
Q: Why does my result show NaN?
A: Almost always because an input was empty or contained non-numeric text when you clicked calculate. Our validation with parseFloat and the falsy check guards against this.
Q: How can I put this project on my resume or portfolio?
A: Deploy it free on GitHub Pages or Netlify, write two lines about what it does and what you learned, and link the live demo. Recruiters value finished, deployed, documented work far more than tutorial certificates.
Keep reading
Build a Random Password Generator in JavaScript (Beginner Project)
Build a random password generator in JavaScript — length slider, character options, copy button, strength meter, and why crypto.getRandomValues beats Math.random.
Read article
Free Invoice Format in Excel for Indian Freelancers (2026 Guide)
Free Excel invoice format for Indian freelancers — GST-compliant fields, step-by-step setup, essential formulas, and common mistakes to avoid in 2026.
Read article
How to Calculate EMI for Home Loans in India: 2026 Guide
Learn how home loan EMI is calculated in India with the official formula, a worked ₹40 lakh example, and smart 2026 tips to lower your monthly payments.
Read article