โ† Back to all guides
๐Ÿง˜โ€โ™€๏ธ

Build a Self-Care Tracker App

Track your water, sleep, mood, skincare, and workouts with a cute app you built yourself.

Projectsbeginner8 min read

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, // glasses
5sleep: 7.5, // hours
6mood: 'great', // great, good, meh, rough
7skincare: {
8morning: true,
9night: false,
10},
11movement: true,
12note: 'Had a really productive day! Finally fixed that bug.',
13};
14
15// Mood options with emojis
16const 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';
2
3function WaterTracker({ glasses, onUpdate }) {
4const goal = 8; // daily goal
5
6return (
7<div className='tracker-card'>
8<h3>Water</h3>
9<p className='tracker-subtitle'>Goal: {goal} glasses</p>
10
11{/* Visual water glasses */}
12<div className='water-glasses'>
13{Array.from({ length: goal }).map((_, i) => (
14<button
15key={i}
16onClick={() => onUpdate(i + 1)}
17className={`glass ${i < glasses ? 'filled' : 'empty'}`}
18>
19๐Ÿ’ง
20</button>
21))}
22</div>
23
24<p className='tracker-progress'>
25{glasses}/{goal} glasses
26{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];
8
9return (
10<div className='tracker-card'>
11<h3>How are you feeling?</h3>
12<div className='mood-options'>
13{moods.map(mood => (
14<button
15key={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];
6
7return (
8<div className='tracker-card'>
9<h3>Skincare</h3>
10{routines.map(routine => (
11<label key={routine.id} className='checklist-item'>
12<input
13type='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}
7
8// Load today's data
9function 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}
20
21// Get the last 7 days for a weekly view
22function 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';
2
3function SelfCareApp() {
4const today = new Date().toISOString().split('T')[0];
5const [data, setData] = useState(loadDay(today));
6
7// Auto-save whenever data changes
8useEffect(() => {
9saveDay(today, data);
10}, [data, today]);
11
12const updateField = (field, value) => {
13setData(prev => ({ ...prev, [field]: value }));
14};
15
16return (
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>
26
27<MoodPicker
28currentMood={data.mood}
29onSelect={mood => updateField('mood', mood)}
30/>
31
32<WaterTracker
33glasses={data.water}
34onUpdate={count => updateField('water', count)}
35/>
36
37<SkincareTracker
38skincare={data.skincare}
39onToggle={routine => updateField('skincare', {
40...data.skincare,
41[routine]: !data.skincare[routine]
42})}
43/>
44
45{/* Movement toggle */}
46<div className='tracker-card'>
47<h3>Movement</h3>
48<button
49onClick={() => 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>
55
56{/* Daily note */}
57<div className='tracker-card'>
58<h3>Daily Note</h3>
59<textarea
60value={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}
7
8.tracker-card {
9background: white;
10border-radius: 20px;
11padding: 24px;
12margin-bottom: 16px;
13box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
14}
15
16.tracker-card h3 {
17font-size: 1rem;
18margin-bottom: 12px;
19}
20
21.water-glasses {
22display: flex;
23gap: 8px;
24margin: 12px 0;
25}
26
27.glass {
28font-size: 1.5rem;
29background: none;
30border: none;
31cursor: pointer;
32opacity: 0.3;
33transition: all 0.2s;
34}
35
36.glass.filled {
37opacity: 1;
38transform: scale(1.1);
39}
40
41.mood-options {
42display: grid;
43grid-template-columns: repeat(4, 1fr);
44gap: 8px;
45}
46
47.mood-btn {
48padding: 16px 8px;
49border-radius: 16px;
50border: 2px solid #f0f0f0;
51background: white;
52cursor: pointer;
53text-align: center;
54transition: all 0.2s;
55}
56
57.mood-btn.selected {
58border-color: #C4B8E8;
59background: #F3F0FA;
60}
61
62.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 โœจ