An ADHD-Friendly Task & Focus Timer Built in PHP.
Introduction
Managing attention and productivity can be difficult, especially for people with ADHD. Long to‑do lists often feel overwhelming, and big tasks can be discouraging. To solve this, I built a PHP web application that breaks work into micro‑steps, adds a Pomodoro‑style focus timer, and tracks progress visually.
This project demonstrates how simple code can create meaningful tools that support better daily routines.
🎯 Core Features
- Micro-step task management: Break tasks into tiny, actionable steps.
- Pomodoro-style focus timer: 25‑minute focus sessions with 5‑minute breaks.
- Visual progress tracking: Progress bars show completed steps at a glance.
-
Lightweight persistence: Uses a JSON file (
data.json) instead of a database.
🛠️ The Code
Here’s the heart of the application — a single index.php file that handles tasks, steps, and the timer:
<?php
// Simple ADHD-friendly Task + Focus Timer app (no framework, JSON storage)
// Save as index.php, create data.json with [] and run via PHP's built-in server: php -S localhost:8000
$dataFile = __DIR__ . '/data.json';
if (!file_exists($dataFile)) file_put_contents($dataFile, json_encode([]));
function readData() {
global $dataFile;
$json = file_get_contents($dataFile);
$data = json_decode($json, true);
return is_array($data) ? $data : [];
}
function writeData($data) {
global $dataFile;
file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT));
}
// Handle actions
$action = $_POST['action'] ?? $_GET['action'] ?? null;
$data = readData();
if ($action === 'add_task') {
$title = trim($_POST['title'] ?? '');
if ($title !== '') {
$data[] = [
'id' => uniqid('t_', true),
'title' => $title,
'steps' => [],
'done' => false,
'createdAt' => time()
];
writeData($data);
}
header('Location: ./'); exit;
}
if ($action === 'add_step') {
$taskId = $_POST['taskId'] ?? '';
$stepText = trim($_POST['step'] ?? '');
foreach ($data as &$task) {
if ($task['id'] === $taskId && $stepText !== '') {
$task['steps'][] = [
'id' => uniqid('s_', true),
'text' => $stepText,
'done' => false
];
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'toggle_step') {
$taskId = $_POST['taskId'] ?? '';
$stepId = $_POST['stepId'] ?? '';
foreach ($data as &$task) {
if ($task['id'] === $taskId) {
foreach ($task['steps'] as &$step) {
if ($step['id'] === $stepId) {
$step['done'] = !$step['done'];
break;
}
}
unset($step);
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'toggle_task') {
$taskId = $_POST['taskId'] ?? '';
foreach ($data as &$task) {
if ($task['id'] === $taskId) {
$task['done'] = !$task['done'];
break;
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'delete_task') {
$taskId = $_POST['taskId'] ?? '';
$data = array_values(array_filter($data, fn($t) => $t['id'] !== $taskId));
writeData($data);
header('Location: ./'); exit;
}
// Helper
function progress($task) {
$total = count($task['steps']);
if ($total === 0) return 0;
$done = count(array_filter($task['steps'], fn($s) => $s['done']));
return round(($done / $total) * 100);
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ADHD-friendly Task + Focus Timer</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root { --bg:#0f172a; --card:#111827; --text:#e5e7eb; --accent:#22c55e; --muted:#94a3b8; --danger:#ef4444; }
body { background:var(--bg); color:var(--text); font-family:system-ui,-apple-system,Segoe UI,Roboto; margin:0; }
.container { max-width:900px; margin:24px auto; padding:0 16px; }
.grid { display:grid; grid-template-columns: 1fr 320px; gap:16px; }
.card { background:var(--card); border-radius:12px; padding:16px; box-shadow:0 10px 25px rgba(0,0,0,0.25); }
h1,h2 { margin:0 0 12px; }
.row { display:flex; gap:8px; }
input[type="text"] { width:100%; padding:10px; border-radius:8px; border:1px solid #334155; background:#0b1220; color:var(--text); }
button { padding:10px 12px; border:none; border-radius:8px; cursor:pointer; background:#1f2937; color:var(--text); }
button.primary { background:var(--accent); color:#062a12; font-weight:600; }
button.danger { background:var(--danger); }
.task { border:1px solid #334155; border-radius:10px; padding:12px; margin-bottom:10px; }
.progress { height:8px; background:#1f2937; border-radius:999px; overflow:hidden; margin:8px 0; }
.bar { height:100%; background:var(--accent); width:0%; transition:width .25s ease; }
.steps { margin-top:8px; }
.step { display:flex; align-items:center; gap:8px; padding:6px 0; }
.muted { color:var(--muted); font-size:12px; }
.pill { font-size:12px; padding:6px 8px; border:1px dashed #334155; border-radius:999px; display:inline-block; color:var(--muted); }
.timer { text-align:center; }
.big { font-size:52px; font-weight:700; letter-spacing:1px; margin:10px 0; }
.center { display:flex; justify-content:center; gap:8px; }
.success { color:var(--accent); }
</style>
</head>
<body>
<div class="container">
<h1>ADHD-friendly Task + Focus Timer</h1>
<p class="muted">Break work into tiny steps, timebox with short focus sessions, and celebrate quick wins.</p>
<div class="grid">
<div class="card">
<h2>Tasks</h2>
<form method="post" class="row" style="margin-bottom:12px;">
<input type="hidden" name="action" value="add_task">
<input type="text" name="title" placeholder="Add a task (keep it small)" required>
<button class="primary" type="submit">Add</button>
</form>
<?php if (empty($data)): ?>
<p class="muted">No tasks yet. Start with something you can finish in under 25 minutes.</p>
<?php endif; ?>
<?php foreach ($data as $task): ?>
<div class="task">
<div class="row" style="justify-content:space-between;">
<div>
<strong><?php echo htmlspecialchars($task['title']); ?></strong>
<?php if ($task['done']): ?>
<span class="pill success">Done</span>
<?php endif; ?>
</div>
<div class="row">
<form method="post">
<input type="hidden" name="action" value="toggle_task">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<button type="submit"><?php echo $task['done'] ? 'Mark Undone' : 'Mark Done'; ?></button>
</form>
<form method="post">
<input type="hidden" name="action" value="delete_task">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<button class="danger" type="submit">Delete</button>
</form>
</div>
</div>
<div class="progress">
<div class="bar" style="width: <?php echo progress($task); ?>%;"></div>
</div>
<span class="muted"><?php echo progress($task); ?>% micro-steps complete</span>
<div class="steps">
<?php foreach ($task['steps'] as $step): ?>
<div class="step">
<form method="post">
<input type="hidden" name="action" value="toggle_step">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<input type="hidden" name="stepId" value="<?php echo $step['id']; ?>">
<button type="submit"><?php echo $step['done'] ? '✅' : '⬜'; ?></button>
</form>
<span><?php echo htmlspecialchars($step['text']); ?></span>
</div>
<?php endforeach; ?>
<form method="post" class="row">
<input type="hidden" name="action" value="add_step">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<input type="text" name="step" placeholder="Add a tiny step (2–5 min)" required>
<button type="submit">Add step</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="card timer">
<h2>Focus timer</h2>
<div id="mode" class="pill">Focus: 25:00</div>
<div class="big" id="clock">25:00</div>
<div class="center">
<button class="primary" onclick="startTimer()">Start</button>
<button onclick="resetTimer()">Reset</button>
</div>
<p class="muted" id="tip">Tip: Close extra tabs. Put phone away. Pick the smallest next step.</p>
</div>
</div>
</div>
<script>
let mode = 'focus'; // 'focus' or 'break'
let remaining = 25*60; // seconds
let timerId = null;
function render() {
const m = Math.floor(remaining / 60).toString().padStart(2,'0');
const s = (remaining % 60).toString().padStart(2,'0');
document.getElementById('clock').textContent = `${m}:${s}`;
document.getElementById('mode').textContent = (mode === 'focus')
? `Focus: ${m}:${s}` : `Break: ${m}:${s}`;
document.getElementById('tip').textContent = (mode === 'focus')
? 'Tip: Pick one tiny step and do only that.'
: 'Tip: Stand, stretch, sip water. Eyes off screens.';
}
function startTimer() {
if (timerId) return;
timerId = setInterval(() => {
remaining--;
if (remaining <= 0) {
new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA=').play();
if (mode === 'focus') {
mode = 'break'; remaining = 5*60;
} else {
mode = 'focus'; remaining = 25*60;
}
}
render();
}, 1000);
}
function resetTimer() {
clearInterval(timerId); timerId = null;
mode = 'focus'; remaining = 25*60; render();
}
render();
</script>
</body>
</html>
?>
The script uses:
-
readData()andwriteData()to manage JSON storage. -
POST actions (
add_task,add_step,toggle_step, etc.) to update tasks. - JavaScript for the timer logic, switching between focus and break modes.
📊 Workflow Example
- Add a task: “Prepare project report.”
- Break it into micro‑steps: Draft outline → Write intro → Add charts → Review.
- Start the 25‑minute timer and focus only on the first step.
- Check off completed steps and watch the progress bar grow.
- Take a 5‑minute break when the timer signals.
🚀 Why This Matters
For people with ADHD—or anyone struggling with productivity—this app provides:
- Structure without rigidity: Tasks can be broken down endlessly.
- Encouragement through feedback: Progress bars and checkmarks make achievements visible.
-
Simplicity: No database or complex setup, just run
php -S localhost:8000.
💡 Future Enhancements
- Add sound alerts for timer completion.
- Sync tasks with Google Calendar.
- Provide weekly statistics dashboards.
- Enable multi-user support with authentication.
Conclusion
This PHP script application is more than just code — it’s a supportive tool for managing attention and productivity. By combining micro‑step task management with a Pomodoro‑style timer, it helps users stay focused, reduce overwhelm, and celebrate progress.
For developers, it’s also a great portfolio project: practical, lightweight, and impactful.