⚡ToolZip
블로그🛠️ 도구 사용하기
← Blog
🧮 calcSeptember 19, 2026

Building a BMI Calculator — The Math, the Korean Standard, and the Limitations

#javascript#webdev#health#tools

BMI calculators are a common beginner project. The math is straightforward: weight in kg divided by height in meters squared. But implementing one that's actually useful reveals some interesting design decisions — particularly around which standard to apply, how to handle different input units, and how to communicate the limitations of the metric clearly.

The Core Calculation

function calculateBMI(weightKg, heightCm) {
  const heightM = heightCm / 100;
  return weightKg / (heightM * heightM);
}

// Example
const bmi = calculateBMI(70, 175);
// → 22.857...

The Classification Problem

WHO's BMI classifications are widely used:

const WHO_CLASSIFICATIONS = [
  { max: 18.5, label: 'Underweight', risk: 'Malnutrition risk' },
  { max: 25.0, label: 'Normal weight', risk: 'Low risk' },
  { max: 30.0, label: 'Pre-obesity', risk: 'Enhanced risk' },
  { max: 35.0, label: 'Obesity class I', risk: 'Moderate risk' },
  { max: 40.0, label: 'Obesity class II', risk: 'Severe risk' },
  { max: Infinity, label: 'Obesity class III', risk: 'Very severe risk' },
];

But Korean health authorities (대한비만학회) use different thresholds. Asian populations tend to carry proportionally more body fat at the same BMI compared to European populations, and experience obesity-related health risks at lower BMI values:

const KOREAN_CLASSIFICATIONS = [
  { max: 18.5, label: '저체중', labelEn: 'Underweight' },
  { max: 23.0, label: '정상', labelEn: 'Normal' },
  { max: 25.0, label: '비만 전단계', labelEn: 'Pre-obese' },
  { max: 30.0, label: '1단계 비만', labelEn: 'Obesity Class I' },
  { max: 35.0, label: '2단계 비만', labelEn: 'Obesity Class II' },
  { max: Infinity, label: '3단계 비만', labelEn: 'Obesity Class III' },
];

Notice: the Korean standard marks BMI ≥ 23 as "pre-obese" versus WHO's ≥ 25 for "overweight." This 2-point difference can meaningfully change the classification for a large portion of the population.

function classify(bmi, standard = 'korean') {
  const classifications = standard === 'korean' 
    ? KOREAN_CLASSIFICATIONS 
    : WHO_CLASSIFICATIONS;
  
  return classifications.find(c => bmi < c.max);
}

Handling Both Imperial and Metric Input

Users from different regions prefer different units. Supporting both requires careful conversion:

function calculateBMIFromImperial(weightLbs, heightFt, heightIn = 0) {
  const totalInches = heightFt * 12 + heightIn;
  const heightM = totalInches * 0.0254;
  const weightKg = weightLbs * 0.453592;
  return weightKg / (heightM * heightM);
}

function calculateBMIFromMetric(weightKg, heightCm) {
  const heightM = heightCm / 100;
  return weightKg / (heightM * heightM);
}

A React component that handles both:

function BMICalculator() {
  const [unit, setUnit] = useState('metric');
  const [inputs, setInputs] = useState({
    weightKg: '', heightCm: '',
    weightLbs: '', heightFt: '', heightIn: '',
  });
  const [result, setResult] = useState(null);

  const calculate = () => {
    let bmi;
    if (unit === 'metric') {
      const w = parseFloat(inputs.weightKg);
      const h = parseFloat(inputs.heightCm);
      if (!w || !h || h <= 0) return;
      bmi = calculateBMIFromMetric(w, h);
    } else {
      const w = parseFloat(inputs.weightLbs);
      const ft = parseFloat(inputs.heightFt) || 0;
      const inch = parseFloat(inputs.heightIn) || 0;
      if (!w || (!ft && !inch)) return;
      bmi = calculateBMIFromImperial(w, ft, inch);
    }
    
    setResult({
      bmi: Math.round(bmi * 10) / 10,
      classification: classify(bmi, 'korean'),
      normalRange: calculateNormalRange(
        unit === 'metric' ? parseFloat(inputs.heightCm) : null
      ),
    });
  };

  // ... render
}

Calculating the Normal Weight Range

Users often want to know not just their classification but their target range:

function calculateNormalRange(heightCm, standard = 'korean') {
  const heightM = heightCm / 100;
  
  const [minBMI, maxBMI] = standard === 'korean' ? [18.5, 22.9] : [18.5, 24.9];
  
  return {
    minKg: Math.round(minBMI * heightM * heightM * 10) / 10,
    maxKg: Math.round(maxBMI * heightM * heightM * 10) / 10,
    minLbs: Math.round(minBMI * heightM * heightM * 2.20462 * 10) / 10,
    maxLbs: Math.round(maxBMI * heightM * heightM * 2.20462 * 10) / 10,
  };
}

// Example for 170cm
const range = calculateNormalRange(170, 'korean');
// → { minKg: 53.5, maxKg: 66.2, minLbs: 117.9, maxLbs: 145.9 }

Communicating BMI's Limitations Clearly

BMI is a population-level screening tool, not an individual health assessment. The limitations are real and worth surfacing in your UI:

Muscle vs. fat: BMI measures weight relative to height, not body composition. A highly muscular person can have a high BMI with low body fat. An older person can have a "normal" BMI while having high body fat and low muscle mass.

Distribution: Where fat is stored matters more than total fat. Abdominal fat is metabolically more active and more associated with cardiovascular risk than subcutaneous fat. BMI doesn't capture distribution.

Population-specific: The Korean/Asian standard exists precisely because BMI's predictive value varies by ethnicity. A BMI that predicts a certain level of metabolic risk for a European population predicts different risk levels for an Asian population.

Age and sex: A 60-year-old and a 25-year-old with the same BMI have very different health profiles. Women generally have higher body fat percentages than men at the same BMI.

function BMIDisclaimer() {
  return (
    <div className="disclaimer">
      <p>
        BMI is a screening tool, not a diagnostic measure. It doesn't 
        account for muscle mass, age, sex, or fat distribution. 
        Consult a healthcare provider for a complete health assessment.
      </p>
    </div>
  );
}

Validation Edge Cases

function validateBMIInputs(weight, height) {
  const errors = [];
  
  if (weight <= 0) errors.push('Weight must be positive');
  if (height <= 0) errors.push('Height must be positive');
  
  // Sanity checks for human plausible values
  if (weight > 500) errors.push('Weight exceeds plausible human range');
  if (height < 50 || height > 300) errors.push('Height is outside plausible range (cm)');
  
  // Extremely low BMI values
  const bmi = calculateBMIFromMetric(weight, height);
  if (bmi < 10) errors.push('Result is below medically possible BMI');
  if (bmi > 100) errors.push('Result exceeds medically recorded maximum BMI');
  
  return errors;
}

Try It

ToolZip's BMI calculator applies Korean health standards, supports both metric and imperial input, calculates the normal weight range for your height, and works entirely in the browser.

toolzip.app/tools/bmi-calculator


ToolZip — 48 free browser-based tools. Everything runs client-side.

🛠️
Try the tool now
No install · Free · No server upload
Open tool →