"I've felt off lately, but I can't pinpoint why." "Last month felt so much better — what was different?" These questions are hard to answer without data.
Tracking your emotions creates visibility. Over time, patterns emerge — the connection between sleep, exercise, relationships, and how you feel. Today we'll build a mood tracker app with Rork, no coding needed.
What You'll Build
The finished app will include:
- A 5-level mood score recorded each day (from great to terrible)
- Emoji-based selection UI that makes daily check-ins quick and easy
- An optional short diary note for each entry
- A calendar history view color-coded by mood
- Weekly and monthly trend graphs
Step-by-Step Development in Rork
Step 1: Create a New Project
Log in to Rork (rork.app) and create a new project. Name it "MoodTracker" and hit Start.
Step 2: Describe Your App to Rork
Paste the following prompt into Rork's chat panel:
Build a mood and emotion tracking app.
Features needed:
1. Daily mood check-in
- Select a mood score from 1 to 5 (1=Terrible, 2=Bad, 3=Okay, 4=Good, 5=Great)
- Display an emoji for each score (😢😟😐🙂😊)
- Optional short diary note (free text)
- Optional category tags (Work, Family, Health, Hobby, Other)
2. History view
- Calendar view with each day color-coded by mood score
- List view showing the 30 most recent entries
- Tap any entry to see the full details
3. Trend graph
- Line graph of mood scores for the past 7 days
- Bar chart of monthly average scores
4. Data persistence
- All data stored locally
- Entries survive app restarts
Design:
- Soft, calming pastel color palette
- Large emoji icons for easy one-tap selection
- Simple enough for a quick daily check-in
Step 3: Review the Generated Code
Here's what Rork generates for the core pieces.
Mood data type definitions (TypeScript):
// types/mood.ts
export type MoodScore = 1 | 2 | 3 | 4 | 5;
export type MoodCategory =
'work' | 'family' | 'health' | 'hobby' | 'other';
export interface MoodEntry {
id: string;
date: string; // YYYY-MM-DD format
score: MoodScore;
note: string;
categories: MoodCategory[];
createdAt: string;
}
// Display config mapped to each score
export const MOOD_CONFIG: Record<MoodScore, {
emoji: string;
label: string;
color: string;
bgColor: string;
}> = {
1: { emoji: '😢', label: 'Terrible', color: '#EF5350', bgColor: '#FFEBEE' },
2: { emoji: '😟', label: 'Bad', color: '#FF7043', bgColor: '#FBE9E7' },
3: { emoji: '😐', label: 'Okay', color: '#FFA726', bgColor: '#FFF3E0' },
4: { emoji: '🙂', label: 'Good', color: '#66BB6A', bgColor: '#E8F5E9' },
5: { emoji: '😊', label: 'Great', color: '#42A5F5', bgColor: '#E3F2FD' },
};
export const CATEGORY_CONFIG: Record<MoodCategory, {
label: string;
icon: string;
}> = {
work: { label: 'Work', icon: '💼' },
family: { label: 'Family', icon: '👨👩👧' },
health: { label: 'Health', icon: '💪' },
hobby: { label: 'Hobby', icon: '🎨' },
other: { label: 'Other', icon: '⭐' },
};Today's check-in screen:
// app/(tabs)/index.tsx
import React, { useState } from 'react';
import {
View, Text, TouchableOpacity, TextInput,
StyleSheet, ScrollView, Alert
} from 'react-native';
import { useMoodStore } from '@/store/moodStore';
import { MOOD_CONFIG, CATEGORY_CONFIG } from '@/types/mood';
import type { MoodScore, MoodCategory } from '@/types/mood';
import { getTodayString } from '@/utils/dateUtils';
export default function TodayScreen() {
const { entries, addEntry } = useMoodStore();
const today = getTodayString();
const todayEntry = entries.find(e => e.date === today);
const [selectedScore, setSelectedScore] = useState<MoodScore | null>(null);
const [note, setNote] = useState('');
const [selectedCategories, setSelectedCategories] = useState<MoodCategory[]>([]);
const toggleCategory = (cat: MoodCategory) => {
setSelectedCategories(prev =>
prev.includes(cat) ? prev.filter(c => c !== cat) : [...prev, cat]
);
};
const handleSave = () => {
if (!selectedScore) {
Alert.alert('Please select a mood score');
return;
}
addEntry({
id: Date.now().toString(),
date: today,
score: selectedScore,
note,
categories: selectedCategories,
createdAt: new Date().toISOString(),
});
Alert.alert('✅ Entry saved!');
};
// Already logged today
if (todayEntry) {
const config = MOOD_CONFIG[todayEntry.score];
return (
<View style={[styles.container, { backgroundColor: config.bgColor }]}>
<Text style={styles.savedTitle}>Today's mood is logged</Text>
<Text style={styles.savedEmoji}>{config.emoji}</Text>
<Text style={[styles.savedLabel, { color: config.color }]}>
{config.label}
</Text>
{todayEntry.note ? (
<Text style={styles.savedNote}>"{todayEntry.note}"</Text>
) : null}
</View>
);
}
return (
<ScrollView style={styles.container}>
<Text style={styles.dateText}>{today}</Text>
<Text style={styles.questionText}>How are you feeling today?</Text>
{/* Mood score selector */}
<View style={styles.moodRow}>
{([1, 2, 3, 4, 5] as MoodScore[]).map(score => {
const config = MOOD_CONFIG[score];
const isSelected = selectedScore === score;
return (
<TouchableOpacity
key={score}
style={[
styles.moodButton,
{ backgroundColor: isSelected ? config.color : '#F5F5F5' }
]}
onPress={() => setSelectedScore(score)}
>
<Text style={styles.moodEmoji}>{config.emoji}</Text>
<Text style={[
styles.moodLabel,
{ color: isSelected ? '#fff' : '#666' }
]}>
{config.label}
</Text>
</TouchableOpacity>
);
})}
</View>
{/* Category tags */}
<Text style={styles.sectionTitle}>What influenced your mood? (optional)</Text>
<View style={styles.categoryRow}>
{(Object.entries(CATEGORY_CONFIG) as [MoodCategory, { label: string; icon: string }][]).map(
([cat, { label, icon }]) => {
const isSelected = selectedCategories.includes(cat);
return (
<TouchableOpacity
key={cat}
style={[styles.categoryChip, isSelected && styles.categoryChipSelected]}
onPress={() => toggleCategory(cat)}
>
<Text>{icon} {label}</Text>
</TouchableOpacity>
);
}
)}
</View>
{/* Diary note */}
<Text style={styles.sectionTitle}>Quick note (optional)</Text>
<TextInput
style={styles.noteInput}
placeholder="What happened today? How did it feel?"
multiline
value={note}
onChangeText={setNote}
maxLength={200}
/>
<TouchableOpacity
style={[styles.saveButton, !selectedScore && styles.saveButtonDisabled]}
onPress={handleSave}
disabled={!selectedScore}
>
<Text style={styles.saveButtonText}>Save entry</Text>
</TouchableOpacity>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#FAFAFA', padding: 20 },
dateText: { fontSize: 14, color: '#888', marginBottom: 4 },
questionText: { fontSize: 22, fontWeight: '700', color: '#1a1a1a', marginBottom: 20 },
moodRow: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 24 },
moodButton: {
flex: 1, marginHorizontal: 4, borderRadius: 12, padding: 10,
alignItems: 'center',
},
moodEmoji: { fontSize: 28, marginBottom: 4 },
moodLabel: { fontSize: 11, fontWeight: '600' },
sectionTitle: { fontSize: 15, fontWeight: '600', color: '#333', marginBottom: 10 },
categoryRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 8, marginBottom: 24 },
categoryChip: {
paddingHorizontal: 14, paddingVertical: 8, borderRadius: 20,
backgroundColor: '#F0F0F0',
},
categoryChipSelected: { backgroundColor: '#C8E6C9' },
noteInput: {
backgroundColor: '#fff', borderRadius: 12, padding: 14,
minHeight: 80, fontSize: 15, textAlignVertical: 'top',
borderWidth: 1, borderColor: '#E0E0E0', marginBottom: 24,
},
saveButton: {
backgroundColor: '#42A5F5', borderRadius: 14, padding: 16, alignItems: 'center',
},
saveButtonDisabled: { backgroundColor: '#BDBDBD' },
saveButtonText: { color: '#fff', fontSize: 17, fontWeight: '700' },
savedTitle: { fontSize: 18, color: '#555', textAlign: 'center', marginBottom: 16 },
savedEmoji: { fontSize: 72, textAlign: 'center', marginBottom: 12 },
savedLabel: { fontSize: 24, fontWeight: '700', textAlign: 'center', marginBottom: 8 },
savedNote: { fontSize: 16, color: '#666', textAlign: 'center', fontStyle: 'italic' },
});Step 4: Add the History View
Continue in chat:
Add a history screen showing past mood entries.
- List the 30 most recent entries with emoji, score, date, and note
- Also add a calendar tab where each day is color-coded by mood score
- Tapping an entry shows the full details
Step 5: Add Trend Graphs
Create a stats screen with the following:
- A line graph of mood scores for the past 7 days (use recharts or victory-native)
- This month's average score
- A ranking of which category tags appeared most often
Step 6: Preview and Verify
Preview the app and add 3 days of test entries.
Confirm that the history list and graph display correctly.
Customization Ideas
Once the basic app works, here are ways to take it further:
Idea 1: Evening Reminder Notifications
Send a push notification at 9 PM each evening with the message
"Time to log today's mood." Let users set a custom reminder time.
Idea 2: AI Mood Coaching
After each check-in, use Rork's built-in AI generation to provide
a short personalized message or tip based on the user's score and note.
Keep it warm and encouraging rather than clinical.
Idea 3: CSV Export
Add a feature to export all mood history as a CSV file.
The file should be shareable via the native share sheet so users can
save it to their files app or send it by email.
Wrap-Up
A mood tracker is one of the most valuable personal tools you can build — simple on the surface, but genuinely illuminating over time.
Key takeaways from this tutorial:
- Emoji-based ratings lower the friction of daily check-ins dramatically
- Category tags help you identify what's actually driving your mood
- Graphs and calendars turn raw data into self-awareness
- Incremental feature additions keep development manageable and fun
Start logging. Patterns you never expected will emerge within a few weeks.
For more Rork tutorials, see the Rork Habit Tracker Tutorial and the Rork Journal and Diary App Tutorial.