JavascriptIntermediate
Student Grade Calculator
Build a grade calculator that takes multiple subject scores and calculates the total, average, and letter grade.
Student Grade Calculator
Problem
Build a grade calculator where the user can add multiple subjects with their scores. The app calculates the total, average, and an overall letter grade — and shows the grade for each subject too.
Subjects added:
Math: 85
Science: 72
English: 91
Output:
Total: 248
Average: 82.67
Overall Grade: B
Per subject:
Math: 85 → B
Science: 72 → C
English: 91 → AGrading Scale
90 - 100 → A
80 - 89 → B
70 - 79 → C
60 - 69 → D
Below 60 → FLogic
- Select inputs for subject name, score, add button, and results area
- Store subjects in an array — each with a name and score
- On add — validate inputs and push to the array
- Render each subject with its individual grade
- Calculate total and average from all scores
- Determine overall grade from the average
- Allow removing a subject — recalculate everything
Flow
HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Student Grade Calculator</title>
<style>
body {
font-family: sans-serif;
max-width: 480px;
margin: 60px auto;
padding: 0 20px;
}
.input-row {
display: flex;
gap: 10px;
margin-bottom: 16px;
}
.input-row input {
padding: 12px;
font-size: 1rem;
border: 2px solid #ccc;
border-radius: 8px;
outline: none;
box-sizing: border-box;
}
#subject-name {
flex: 2;
}
#subject-score {
flex: 1;
}
.input-row input:focus {
border-color: #555;
}
.input-row button {
padding: 12px 20px;
font-size: 1rem;
font-weight: 600;
background: #111;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
}
.input-row button:hover {
opacity: 0.85;
}
#error {
color: #c0392b;
font-size: 0.9rem;
margin-bottom: 12px;
display: none;
}
/* subject list */
#subject-list {
list-style: none;
padding: 0;
margin: 0 0 20px;
}
#subject-list li {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
border: 1px solid #e0e0e0;
border-radius: 8px;
margin-bottom: 8px;
}
#subject-list .subject-name {
flex: 1;
font-size: 1rem;
color: #333;
}
#subject-list .subject-score {
font-weight: 600;
color: #111;
}
/* grade badge — color depends on grade */
.grade-badge {
padding: 4px 10px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 700;
color: #fff;
min-width: 28px;
text-align: center;
}
.grade-A { background: #1a7a3f; }
.grade-B { background: #3498db; }
.grade-C { background: #f39c12; }
.grade-D { background: #e67e22; }
.grade-F { background: #c0392b; }
.remove-btn {
background: none;
border: none;
cursor: pointer;
font-size: 1.1rem;
color: #ccc;
}
.remove-btn:hover {
color: #e74c3c;
}
/* summary box */
#summary {
display: none;
background: #f5f5f5;
border-radius: 10px;
padding: 16px 20px;
}
.summary-row {
display: flex;
justify-content: space-between;
padding: 6px 0;
font-size: 1rem;
color: #333;
}
.summary-row .value {
font-weight: 700;
color: #111;
}
</style>
</head>
<body>
<h1>Grade Calculator</h1>
<div class="input-row">
<input type="text" id="subject-name" placeholder="Subject name" />
<input type="number" id="subject-score" placeholder="Score" />
<button id="add-btn">Add</button>
</div>
<div id="error"></div>
<!-- list of subjects with grades -->
<ul id="subject-list"></ul>
<!-- overall summary -->
<div id="summary">
<div class="summary-row">
<span>Total</span>
<span class="value" id="summary-total">0</span>
</div>
<div class="summary-row">
<span>Average</span>
<span class="value" id="summary-average">0</span>
</div>
<div class="summary-row">
<span>Overall Grade</span>
<span class="value" id="summary-grade">-</span>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Solution
// Step 1 — select elements
const subjectNameInput = document.querySelector("#subject-name");
const subjectScoreInput = document.querySelector("#subject-score");
const addBtn = document.querySelector("#add-btn");
const error = document.querySelector("#error");
const subjectList = document.querySelector("#subject-list");
const summary = document.querySelector("#summary");
// Step 2 — array to store all subjects
// each subject is { name, score }
let subjects = [];
// Step 3 — listen for add button click
addBtn.addEventListener("click", addSubject);
// also trigger on Enter in either input
[subjectNameInput, subjectScoreInput].forEach((input) => {
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") addSubject();
});
});
function addSubject() {
const name = subjectNameInput.value.trim();
const scoreValue = subjectScoreInput.value.trim();
// Step 4 — validate inputs
if (!name) {
showError("Please enter a subject name.");
return;
}
if (!scoreValue) {
showError("Please enter a score.");
return;
}
const score = Number(scoreValue);
if (isNaN(score) || score < 0 || score > 100) {
showError("Score must be a number between 0 and 100.");
return;
}
// Step 5 — add to subjects array
subjects.push({ name, score });
// clear inputs
subjectNameInput.value = "";
subjectScoreInput.value = "";
hideError();
// re-render everything
render();
// focus back on subject name for quick entry
subjectNameInput.focus();
}
// Step 6 — grade calculation function
// returns a letter grade for a given numeric score
function getGrade(score) {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
if (score >= 60) return "D";
return "F";
}
function render() {
// clear current list
subjectList.innerHTML = "";
if (subjects.length === 0) {
summary.style.display = "none";
return;
}
// Step 7 — render each subject with its grade
subjects.forEach((subject, index) => {
const grade = getGrade(subject.score);
const li = document.createElement("li");
li.innerHTML = `
<span class="subject-name">${subject.name}</span>
<span class="subject-score">${subject.score}</span>
<span class="grade-badge grade-${grade}">${grade}</span>
<button class="remove-btn" data-index="${index}">✕</button>
`;
subjectList.appendChild(li);
});
// Step 8 — calculate total
// reduce sums all scores together
const total = subjects.reduce((sum, subject) => sum + subject.score, 0);
// Step 9 — calculate average
const average = total / subjects.length;
// Step 10 — overall grade is based on the average
const overallGrade = getGrade(average);
// Step 11 — display summary
summary.style.display = "block";
document.querySelector("#summary-total").textContent = total;
document.querySelector("#summary-average").textContent = average.toFixed(2);
const gradeElement = document.querySelector("#summary-grade");
gradeElement.textContent = overallGrade;
// reset classes then apply the right grade color
gradeElement.className = `value grade-${overallGrade}`;
}
// Step 12 — remove subject — event delegation on the list
subjectList.addEventListener("click", (e) => {
if (!e.target.classList.contains("remove-btn")) return;
// read the index stored on the button
const index = Number(e.target.dataset.index);
// remove that subject from the array
subjects.splice(index, 1);
render();
});
function showError(message) {
error.textContent = message;
error.style.display = "block";
}
function hideError() {
error.style.display = "none";
}Code Execution
Trace through adding "Math" with score 85:
| Step | Code | Result |
|---|---|---|
| Validate name | "Math" not empty | pass |
| Validate score | 85 between 0-100 | pass |
| Push | subjects.push({ name: "Math", score: 85 }) | subjects.length === 1 |
| Get grade | getGrade(85) → 85 >= 80 | "B" |
| Render | li with "Math", 85, badge "B" | shown in list |
Trace through summary after adding Math: 85, Science: 72, English: 91:
| Step | Code | Result |
|---|---|---|
| Total | 85 + 72 + 91 | 248 |
| Average | 248 / 3 | 82.666... |
| Format | .toFixed(2) | "82.67" |
| Overall grade | getGrade(82.666) → 82.666 >= 80 | "B" |
Trace through removing "Science" (index 1):
| Step | Code | Result |
|---|---|---|
| Click remove | e.target.dataset.index | "1" |
| Splice | subjects.splice(1, 1) | removes Science |
| Re-render | subjects = [Math, English] | new total = 85 + 91 = 176 |
| New average | 176 / 2 | 88 |
| New overall grade | getGrade(88) | "B" |
Output
Add Math: 85 → Math 85 — B
Add Science: 72 → Science 72 — C
Add English: 91 → English 91 — A
Summary:
Total: 248
Average: 82.67
Overall Grade: B
Remove Science:
Summary updates to:
Total: 176
Average: 88.00
Overall Grade: B