DEV Community

StudentCalcTools
StudentCalcTools

Posted on

I Built a GPA Calculator in Vanilla JavaScript — Here's the Grade Math Nobody Explains

A while back I needed a GPA calculator that wasn't buried under popups and didn't ask me to create an account. So I built one. It sounded like a weekend project. It took three weekends, mostly because grade math is weirder than it looks.

Here's what I learned, with the actual logic.

GPA math is simple until it isn't

The core formula is genuinely simple:

GPA = total quality points / total credit hours
Enter fullscreen mode Exit fullscreen mode

Quality points = grade value x credit hours for each course. An A in a 3-credit course is worth more than an A in a 1-credit lab. Every student knows this. What most calculator tutorials skip is everything around it.

Problem 1: there is no single grading scale

This was the first surprise. A 4.0 scale is not one scale. Schools differ on:

  • Whether A+ is 4.0 or 4.3
  • Where plus/minus grades land (is a B+ 3.3 or 3.33?)
  • Whether F counts as 0.0 (yes, everywhere, but some students forget to include failed courses)

I ended up making the scale configurable with a lookup table instead of hardcoding values:

const GRADE_POINTS = {
  'A+': 4.0, 'A': 4.0, 'A-': 3.7,
  'B+': 3.3, 'B': 3.0, 'B-': 2.7,
  'C+': 2.3, 'C': 2.0, 'C-': 1.7,
  'D+': 1.3, 'D': 1.0, 'D-': 0.7,
  'F': 0.0
};

function coursePoints(grade, credits) {
  return (GRADE_POINTS[grade] ?? 0) * credits;
}

function calculateGPA(courses) {
  let points = 0, hours = 0;
  for (const c of courses) {
    if (c.grade === 'P') continue; // pass/fail excluded
    points += coursePoints(c.grade, c.credits);
    hours += c.credits;
  }
  return hours === 0 ? 0 : points / hours;
}
Enter fullscreen mode Exit fullscreen mode

A config object beats a switch statement here because schools can swap their scale without touching the logic.

Problem 2: weighted GPA is a naming mess

"Weighted GPA" means different things at different schools. Some add +1.0 for AP/IB and +0.5 for honors. Others use a 5.0 or 6.0 scale. A few Texas districts have their own formulas entirely.

The clean way to handle it: keep unweighted GPA as the source of truth, then apply the weight as a separate, clearly labeled adjustment:

function weightedGPA(courses, weights = { AP: 1.0, Honors: 0.5 }) {
  let points = 0, hours = 0;
  for (const c of courses) {
    if (c.grade === 'P') continue;
    const base = GRADE_POINTS[c.grade] ?? 0;
    const bonus = weights[c.level] ?? 0;
    points += (base + bonus) * c.credits;
    hours += c.credits;
  }
  return hours === 0 ? 0 : points / hours;
}
Enter fullscreen mode Exit fullscreen mode

Always show both numbers side by side and label which is which. Students comparing GPAs across schools get confused enough already.

Problem 3: repeated courses

Most schools replace the old grade when you retake a course, but some average the two attempts. My calculator asks the user which policy applies and branches:

  • Replace: only the latest attempt counts toward hours and points
  • Average: both attempts count

This is a UI problem more than a math problem. A small "did you retake this?" toggle per course row solved it.

Problem 4: input validation is half the work

Real users type "a+" instead of "A+", enter 0 credit hours, or paste grades with trailing spaces. Normalizing input before it touches the math saved me from a whole class of bug reports:

function normalizeGrade(input) {
  return input.trim().toUpperCase().replace(/\s+/g, '');
}
Enter fullscreen mode Exit fullscreen mode

Boring code. Extremely worth it.

What I'd do differently

If I started over, I'd separate the grade-scale config into its own JSON file from day one. Schools change scales, and letting users pick "my school's scale" from a dropdown would beat asking them to type grade values manually. That's the next feature.

The whole thing runs client-side with no backend, no account, and no data leaving the browser. Grade data is personal, and there was no reason to store any of it.

If you want to skip the code and just run the numbers, the finished tool is here: GPA Calculator. It handles weighted and unweighted GPA, plus/minus grades, and repeated courses.

Built with vanilla JS, no frameworks, no build step. Sometimes that's all you need.

Top comments (0)