Task Checklist
Tracks activation tasks against real data, with each undone item linking to the place it gets done.
When to Use
Use when:
A user has setup steps left and each one lives somewhere specific — the MyWorkshopr Getting Started list is the canonical case. Done state must be computed from real data, never hardcoded.
Variants
Full — progress, phases, descriptions
The complete form. Descriptions explain the value of each step and disappear once it's done, so the list gets quieter as the user progresses.
Getting started
Four steps to your first workshop that works.
2 of 4 done
-
Plan Build your first agenda (done) Drag a few activities onto the timeline — it takes about five minutes.
-
Plan Save it so it's yours anywhere (done) A saved agenda opens on any device and can be shared with your team.
- Reflect Take the 3-minute DNA quiz Find out which of the five facilitator archetypes matches how you run a room.
- Learn Find an exercise you'd actually run Browse the library and favourite one for your next session.
<?= ws_task_checklist([
['label' => 'Build your first agenda',
'description' => 'Drag a few activities onto the timeline.',
'href' => '/planner/',
'done' => $user->hasPlan(),
'phase' => 'Plan',
'key' => 'build'],
], [
'title' => 'Getting started',
'subtitle' => 'Four steps to your first workshop that works.',
'dismissible' => true,
]) ?>Complete
Every item done. Decide deliberately what happens next — a finished checklist that never goes away becomes clutter.
Getting started
3 of 3 done
-
Plan Build your first agenda (done)
-
Plan Save it so it's yours anywhere (done)
-
Reflect Take the 3-minute DNA quiz (done)
Minimal
No progress bar, no phases, no descriptions — for a short list where the count would be noise.
Set up your team
<?= ws_task_checklist($items, ['title' => 'Set up your team', 'progress' => false]) ?>
States
| State | Behavior |
|---|---|
| Undone | Renders as a link to href with a hollow icon, its description, and a trailing arrow. This is the actionable state. |
| Done | Filled check in --color-success, description hidden, and no longer a link — there's nothing left to do there. |
Undone with no href | Renders as plain text. Valid, but the user is then told what to do without being shown where — supply an href. |
| Progress | On by default: an "x of N done" count and a bar, both computed from the items' done flags. No separate total to keep in sync. |
| Dismissed | dismissible renders a button carrying data-checklist-dismiss. The component doesn't handle the click — wire it and persist the choice, or the checklist returns on the next load. |
| Hover | Undone rows lift their background; done rows are inert. |
| Focus | Undone rows are links with a --focus-ring outline. |
Real-World Usage
The MyWorkshopr activation panel. Every done flag is a query against real state — that's the contract, and it's what stops the list lying to the user.
<?php
$hasPlan = (bool) getPlanCount($userId);
$hasSaved = (bool) getSavedPlanCount($userId);
$hasDna = (bool) getDnaResult($userId);
$hasFav = (bool) getFavouriteCount($userId);
$tasks = [
['label' => 'Build your first agenda', 'href' => '/planner/', 'done' => $hasPlan,
'phase' => 'Plan', 'key' => 'build',
'description' => 'Drag a few activities onto the timeline.'],
['label' => 'Save it so it\'s yours anywhere', 'href' => '/planner/', 'done' => $hasSaved,
'phase' => 'Plan', 'key' => 'save'],
['label' => 'Take the 3-minute DNA quiz', 'href' => '/dna/', 'done' => $hasDna,
'phase' => 'Reflect', 'key' => 'dna'],
['label' => 'Find an exercise you\'d actually run', 'href' => '/library/', 'done' => $hasFav,
'phase' => 'Learn', 'key' => 'library'],
];
// Hide it entirely once everything is done, rather than showing a finished list.
if (in_array(false, array_column($tasks, 'done'), true)):
?>
<?= ws_task_checklist($tasks, ['title' => 'Getting started', 'dismissible' => true]) ?>
<?php endif; ?>
<script>
document.querySelector('[data-checklist-dismiss]')?.addEventListener('click', async () => {
await fetch('/api/prefs.php?action=dismiss_checklist', { method: 'POST' });
document.querySelector('.ws-task-checklist').remove();
});
</script>Options
Checklist options
| Option | Type | Default | Purpose |
|---|---|---|---|
$items | array | [] | Positional. The task definitions, in the order they should be done. |
title | string | 'Getting started' | Heading, set in Fraunces |
subtitle | string | null | Supporting line under the title |
progress | bool | true | Show the "x of N done" count and bar |
dismissible | bool | false | Render the dismiss button. Your JS handles the click. |
id | string | null | Element ID |
class | string | '' | Additional CSS classes |
Item options
| Option | Type | Default | Purpose |
|---|---|---|---|
label | string | required | The task. Phrase it as the outcome the user gets. |
done | bool | false | Completion state. Compute it from real data. |
href | string | null | Where the task happens. Undone items with an href render as links. |
description | string | null | Why it's worth doing. Hidden once done. |
phase | string | null | Uppercase eyebrow — Learn, Plan, Facilitate, Reflect |
key | string | null | Emitted as data-task for JS and analytics |
Accessibility
| Concern | Behavior |
|---|---|
| State icons | The done and todo icons carry aria-hidden="true", so the tick isn't read as stray text. |
| Dismiss button | Labelled aria-label="Hide this checklist" — it says what it does rather than just "close". |
| Keyboard | Undone items are real links in the tab order; done items aren't focusable, which correctly signals there's nothing to do. |
| Focus | Links use --focus-ring with --focus-ring-offset, matching the rest of the platform. |
| Completion state | Worth knowing: done versus undone is conveyed by icon and colour, with no text equivalent on the row. The progress count ("2 of 4 done") carries it for the list as a whole, but an individual row's state isn't announced. If a checklist ships without the progress bar, consider adding visually-hidden text to each row. |
| Link text | The label is the link's accessible name, so it must stand alone in a screen reader's link list — "Build your first agenda" does; "Get started" wouldn't. |
| Contrast | Done uses --color-success, phase eyebrows --phase-learn-dark, descriptions --text-muted — all tested. |
Tokens
| Token | Used for |
|---|---|
--bg-surface / --bg-subtle | Panel background and row hover |
--color-success | Completed check |
--mainsite-primary | Progress bar fill |
--phase-learn-dark | Phase eyebrow |
--gray-100 / --gray-200 / --gray-300 | Dividers, progress track, and the todo icon |
--text-dark / --text-muted / --text-faint | Title, description, and completed-label text |
--focus-ring / --focus-ring-offset | Link focus treatment |
--radius-lg / --radius-2xl / --radius-full | Panel, row, and progress-bar corners |
--text-h3 / --text-body / --text-small / --text-meta / --text-caption | Type scale across title, label, and eyebrow |
--font-heading / --font-body / --font-medium / --font-semibold | Fraunces title, Inter body |
--tracking-wide | Phase eyebrow letter-spacing |
--space-1 through --space-6 | Internal rhythm |
--transition-fast | Row hover |
CSS Classes
| Class | Purpose |
|---|---|
.ws-task-checklist | Panel container |
.ws-task-checklist__header | Title, subtitle, and dismiss row |
.ws-task-checklist__title / __subtitle | Heading text |
.ws-task-checklist__dismiss | Dismiss button, carrying data-checklist-dismiss |
.ws-task-checklist__progress / __progress-bar / __progress-count | Progress display |
.ws-task-checklist__body / __items | List wrappers |
.ws-task-checklist__item / __row | An individual task and its layout row |
.ws-task-checklist__check | State icon holder |
.ws-task-checklist__icon-done / __icon-todo | The two state icons |
.ws-task-checklist__phase | Uppercase phase eyebrow |
.ws-task-checklist__label / __desc | Task text |
.ws-task-checklist__arrow | Trailing arrow on actionable rows |
Files
| File | Purpose |
|---|---|
includes/components/helpers.php | ws_task_checklist() helper function |
includes/components/task-checklist.php | Template — progress calculation and row markup |
includes/components/components.css | Styles (.ws-task-checklist rules) |
No JS file — dismissal is left to the consumer, as noted in States.