FREE 60-MINUTE LESSON • GRADES 7–12 • BEGINNER JAVASCRIPT
Build a mood check-in that reacts to every click
Students create an accessible mini mood tracker with HTML, CSS, and JavaScript—then personalize the feelings, colors, and response messages.
Looking for a beginner JavaScript project for students that feels useful immediately? This one-file activity teaches click events, data attributes, DOM updates, responsive CSS, and basic accessibility. No framework, account, or special software is required.
Important: This is a reflection and coding activity, not a medical or mental-health assessment. The example does not save or transmit a student’s selection.
| Time | 50–60 minutes |
| Level | Beginner JavaScript |
| Skills | HTML buttons, CSS Grid, events, DOM updates |
| Setup | Any text editor and web browser |
What students will learn
1. Structure
Use semantic HTML, buttons, labels, and a live result area.
2. Style
Create a responsive card with CSS Grid, focus states, and motion preferences.
3. Interact
Listen for clicks, read data attributes, and update page content with JavaScript.
Build the project
Step 1: Create one file
Create a folder named mood-check-in. Inside it, create a file named index.html. Keeping everything in one file makes this project easy to copy, test, and share.
Step 2: Paste the complete code
<!doctype html><html lang="en"><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My Mood Check-In</title> <style> :root { font-family: system-ui, sans-serif; color: #172033; background: #f4f1ff; } * { box-sizing: border-box; } body { min-height: 100vh; margin: 0; display: grid; place-items: center; padding: 24px; background: linear-gradient(135deg, #efe9ff, #dff8f3); } .card { width: min(620px, 100%); padding: 34px; text-align: center; background: white; border-radius: 28px; box-shadow: 0 18px 55px rgba(49, 33, 105, 0.16); } .eyebrow { color: #6d4aff; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.1em; } h1 { margin-bottom: 8px; } .moods { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin: 28px 0 20px; } .mood-btn { min-height: 70px; border: 2px solid #e5e0f7; border-radius: 18px; background: #faf9ff; font-size: 2rem; cursor: pointer; transition: transform 160ms ease, border-color 160ms ease; } .mood-btn:hover { transform: translateY(-4px); } .mood-btn:focus-visible { outline: 4px solid #ffd166; outline-offset: 3px; } .mood-btn[aria-pressed="true"] { border-color: #6d4aff; background: #efeaff; } .result { min-height: 54px; padding: 14px; border-radius: 14px; background: #effaf7; font-weight: 700; } .reset { border: 0; background: transparent; color: #5639d4; font-weight: 700; cursor: pointer; } .privacy { margin-top: 22px; color: #667085; font-size: 0.85rem; } @media (max-width: 520px) { .moods { grid-template-columns: repeat(3, 1fr); } } @media (prefers-reduced-motion: reduce) { * { transition: none !important; } } </style></head><body> <main class="card"> <p class="eyebrow">MY 10-SECOND CHECK-IN</p> <h1>How are you feeling?</h1> <p>Choose the emoji that fits best right now.</p> <div class="moods" role="group" aria-label="Choose your mood"> <button class="mood-btn" data-mood="energized" aria-label="Energized" aria-pressed="false">⚡</button> <button class="mood-btn" data-mood="happy" aria-label="Happy" aria-pressed="false">😊</button> <button class="mood-btn" data-mood="calm" aria-label="Calm" aria-pressed="false">😌</button> <button class="mood-btn" data-mood="tired" aria-label="Tired" aria-pressed="false">😴</button> <button class="mood-btn" data-mood="overwhelmed" aria-label="Overwhelmed" aria-pressed="false">😵💫</button> </div> <p id="result" class="result" aria-live="polite">Pick a mood to begin.</p> <button id="reset" class="reset">Reset check-in</button> <p class="privacy">Nothing is stored or sent anywhere.</p> </main> <script> const buttons = document.querySelectorAll(".mood-btn"); const result = document.querySelector("#result"); const reset = document.querySelector("#reset"); buttons.forEach(function (button) { button.addEventListener("click", function () { buttons.forEach(function (item) { item.setAttribute("aria-pressed", "false"); }); button.setAttribute("aria-pressed", "true"); const mood = button.dataset.mood; result.textContent = "Today's check-in: " + mood + ". Thanks for noticing how you feel."; }); }); reset.addEventListener("click", function () { buttons.forEach(function (button) { button.setAttribute("aria-pressed", "false"); }); result.textContent = "Pick a mood to begin."; }); </script></body></html>
Step 3: Open and test
Save the file, then open index.html in a browser. Click every mood button, test Reset, use the Tab key to move through the buttons, and shrink the browser window to check the mobile layout.
How the JavaScript works
- querySelectorAll collects every mood button.
- forEach gives each button the same click behavior.
- dataset.mood reads the custom feeling stored in each button.
- textContent changes the message without reloading the page.
- aria-pressed tells assistive technology which choice is active.
Customization challenge ladder
Start here
- Change the five emojis and mood names.
- Choose a new background gradient.
- Rewrite the response message in your own voice.
Stretch your skills
- Add a sixth feeling and keep the mobile grid balanced.
- Show a different encouraging message for each mood.
- Add the current date with JavaScript.
Advanced extension
Create a private on-device history with localStorage. First discuss what mood data should—and should not—be collected, shared, or stored.
Teacher-ready lesson plan
- 5 minutes — Notice: What makes a digital check-in feel welcoming and safe?
- 10 minutes — Predict: Students underline the HTML, CSS, and JavaScript sections before running the code.
- 20 minutes — Build: Paste, save, test, and fix any typing errors.
- 15 minutes — Personalize: Complete at least two customization challenges.
- 10 minutes — Share: Partners test keyboard navigation and explain one JavaScript line.
Accessibility and privacy checklist
- Every emoji button has a readable aria-label.
- The selected state is visible and announced with aria-pressed.
- The result uses aria-live so screen readers hear changes.
- Keyboard focus has a high-contrast outline.
- Reduced-motion preferences are respected.
- The starter project does not store names, moods, accounts, or personal data.
Exit ticket
- What event makes the page react?
- Where is each mood name stored?
- What did you change to make the project yours?
- What privacy rule would you add before saving mood history?
Keep building
New to HTML and CSS? Start with the Kindness Card project. Ready to explore more topics? Visit Learn to Code or read Our Story.
