Build a Self-Care Tracker App
Track your water, sleep, mood, skincare, and workouts with a cute app you built yourself.
Build a Self-Care Tracker App
You've downloaded a million self-care apps. They're either ugly, full of ads, or track things you don't care about. What if you built your own? One that tracks exactly what matters to YOU, looks cute, and doesn't cost $9.99/month?
๐ก Pro tip
Want to see the finished app first? Try the live demo and come back to learn how it works!
What We're Building
A daily tracker for:
- Water intake (glasses per day)
- Sleep hours
- Mood (emoji-based, obviously)
- Skincare routine (morning/night checklist)
- Movement (did you move your body today?)
- A daily affirmation or journal note
๐ฌ Denise says
This app taught me localStorage, date handling, and state management โ all because I wanted to know if I was drinking enough water. Learning is so much easier when you're building something for yourself.
Step 1: The Data Structure
1// What one day of tracking looks like:2const todayEntry = {3date: '2025-04-25',4water: 6, // glasses5sleep: 7.5, // hours6mood: 'great', // great, good, meh, rough7skincare: {8morning: true,9night: false,10},11movement: true,12note: 'Had a really productive day! Finally fixed that bug.',13};1415// Mood options with emojis16const moods = {17great: { emoji: 'โจ', label: 'Amazing', color: '#C4B8E8' },18good: { emoji: '๐', label: 'Good', color: '#A8D8EA' },19meh: { emoji: '๐', label: 'Meh', color: '#F0D9A0' },20rough: { emoji: '๐', label: 'Rough day', color: '#F2A5C0' },21};
Step 2: Water Tracker Component
1import { useState } from 'react';23function WaterTracker({ glasses, onUpdate }) {4const goal = 8; // daily goal56return (7<div className='tracker-card'>8<h3>Water</h3>9<p className='tracker-subtitle'>Goal: {goal} glasses</p>1011{/* Visual water glasses */}12<div className='water-glasses'>13{Array.from({ length: goal }).map((_, i) => (14<button15key={i}16onClick={() => onUpdate(i + 1)}17className={`glass ${i < glasses ? 'filled' : 'empty'}`}18>19๐ง20</button>21))}22</div>2324<p className='tracker-progress'>25{glasses}/{goal} glasses26{glasses >= goal && ' โ you did it! ๐'}27</p>28</div>29);30}
Step 3: Mood Picker
1function MoodPicker({ currentMood, onSelect }) {2const moods = [3{ id: 'great', emoji: 'โจ', label: 'Amazing' },4{ id: 'good', emoji: '๐', label: 'Good' },5{ id: 'meh', emoji: '๐', label: 'Meh' },6{ id: 'rough', emoji: '๐', label: 'Rough day' },7];89return (10<div className='tracker-card'>11<h3>How are you feeling?</h3>12<div className='mood-options'>13{moods.map(mood => (14<button15key={mood.id}16onClick={() => onSelect(mood.id)}17className={`mood-btn ${currentMood === mood.id ? 'selected' : ''}`}18>19<span className='mood-emoji'>{mood.emoji}</span>20<span className='mood-label'>{mood.label}</span>21</button>22))}23</div>24</div>25);26}
Step 4: Skincare Checklist
1function SkincareTracker({ skincare, onToggle }) {2const routines = [3{ id: 'morning', label: 'Morning routine', emoji: '๐ ' },4{ id: 'night', label: 'Night routine', emoji: '๐' },5];67return (8<div className='tracker-card'>9<h3>Skincare</h3>10{routines.map(routine => (11<label key={routine.id} className='checklist-item'>12<input13type='checkbox'14checked={skincare[routine.id]}15onChange={() => onToggle(routine.id)}16/>17<span className='checkmark'></span>18<span>{routine.emoji} {routine.label}</span>19</label>20))}21</div>22);23}
Step 5: Save Data with localStorage
1// Save today's data to localStorage (persists between sessions)2function saveDay(date, data) {3const allData = JSON.parse(localStorage.getItem('selfcare') || '{}');4allData[date] = data;5localStorage.setItem('selfcare', JSON.stringify(allData));6}78// Load today's data9function loadDay(date) {10const allData = JSON.parse(localStorage.getItem('selfcare') || '{}');11return allData[date] || {12water: 0,13sleep: 0,14mood: null,15skincare: { morning: false, night: false },16movement: false,17note: '',18};19}2021// Get the last 7 days for a weekly view22function getWeekData() {23const days = [];24for (let i = 6; i >= 0; i--) {25const date = new Date();26date.setDate(date.getDate() - i);27const dateStr = date.toISOString().split('T')[0];28days.push({29date: dateStr,30...loadDay(dateStr),31});32}33return days;34}
Step 6: Putting It All Together
1import { useState, useEffect } from 'react';23function SelfCareApp() {4const today = new Date().toISOString().split('T')[0];5const [data, setData] = useState(loadDay(today));67// Auto-save whenever data changes8useEffect(() => {9saveDay(today, data);10}, [data, today]);1112const updateField = (field, value) => {13setData(prev => ({ ...prev, [field]: value }));14};1516return (17<div className='self-care-app'>18<header>19<h1>Daily Check-in</h1>20<p className='date'>{new Date().toLocaleDateString('en-US', {21weekday: 'long',22month: 'long',23day: 'numeric'24})}</p>25</header>2627<MoodPicker28currentMood={data.mood}29onSelect={mood => updateField('mood', mood)}30/>3132<WaterTracker33glasses={data.water}34onUpdate={count => updateField('water', count)}35/>3637<SkincareTracker38skincare={data.skincare}39onToggle={routine => updateField('skincare', {40...data.skincare,41[routine]: !data.skincare[routine]42})}43/>4445{/* Movement toggle */}46<div className='tracker-card'>47<h3>Movement</h3>48<button49onClick={() => updateField('movement', !data.movement)}50className={`movement-btn ${data.movement ? 'active' : ''}`}51>52{data.movement ? 'Yes! I moved today ๐ช' : 'Did you move today?'}53</button>54</div>5556{/* Daily note */}57<div className='tracker-card'>58<h3>Daily Note</h3>59<textarea60value={data.note}61onChange={e => updateField('note', e.target.value)}62placeholder='How was your day? Any wins? Anything on your mind?'63rows={3}64/>65</div>66</div>67);68}
Step 7: Make It Cute (CSS)
1.self-care-app {2max-width: 480px;3margin: 0 auto;4padding: 24px;5font-family: 'Quicksand', sans-serif;6}78.tracker-card {9background: white;10border-radius: 20px;11padding: 24px;12margin-bottom: 16px;13box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);14}1516.tracker-card h3 {17font-size: 1rem;18margin-bottom: 12px;19}2021.water-glasses {22display: flex;23gap: 8px;24margin: 12px 0;25}2627.glass {28font-size: 1.5rem;29background: none;30border: none;31cursor: pointer;32opacity: 0.3;33transition: all 0.2s;34}3536.glass.filled {37opacity: 1;38transform: scale(1.1);39}4041.mood-options {42display: grid;43grid-template-columns: repeat(4, 1fr);44gap: 8px;45}4647.mood-btn {48padding: 16px 8px;49border-radius: 16px;50border: 2px solid #f0f0f0;51background: white;52cursor: pointer;53text-align: center;54transition: all 0.2s;55}5657.mood-btn.selected {58border-color: #C4B8E8;59background: #F3F0FA;60}6162.mood-emoji {63font-size: 1.5rem;64display: block;65margin-bottom: 4px;66}
Level Up Ideas
- Weekly view โ show a 7-day grid with mood emojis and water progress
- Streaks โ track how many days in a row you've hit your water goal
- Custom habits โ let users add their own trackable habits
- Export data โ download your data as a CSV for analysis
- Period tracker โ add cycle tracking with predictions
- PWA โ make it installable on your phone like a real app
๐ฌ Denise says
You built a self-care app. An app that's actually about YOU and what you need. Not some generic tracker made by a company that wants your data โ one that lives in your browser, looks the way you want, and tracks what matters to you. This is why coding is a superpower. You can build tools that fit your life perfectly.
Photo coming soon โจ
Want to keep going?
Tell me what you want to build next and I'll help you write the code.
Start Building โจ