webdevpuneet.com

Animated Task List — Add, Complete & Delete HTML CSS JS

Animated Task List · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="page">
  <div class="card">
    <div class="card-header">
      <div class="header-left">
        <h2 class="title">My Tasks</h2>
        <span class="count-badge" id="countBadge">0 left</span>
      </div>
      <div class="filters">
        <button class="filter-btn active" data-filter="all">All</button>
        <button class="filter-btn" data-filter="active">Active</button>
        <button class="filter-btn" data-filter="done">Done</button>
      </div>
    </div>

    <form class="add-form" id="addForm">
      <input class="add-input" id="addInput" type="text" placeholder="Add a new task…" maxlength="80" autocomplete="off" aria-label="New task" />
      <button type="submit" class="add-btn" aria-label="Add task">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.8" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
      </button>
    </form>

    <ul class="task-list" id="taskList" role="list" aria-label="Task list" aria-live="polite"></ul>

    <div class="empty-state" id="emptyState" hidden>
      <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="3" y="3" width="18" height="18" rx="4"/><path d="M9 12l2 2 4-4"/></svg>
      <p>No tasks here yet</p>
    </div>

    <div class="card-footer">
      <span class="footer-text" id="footerText"></span>
      <button class="clear-btn" id="clearDoneBtn">Clear done</button>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Spring slide-in for new items
@keyframes slideIn with cubic-bezier(.34,1.56,.64,1) (spring overshoot) + staggered delay (i * 30ms) creates a cascading ripple on list population.
Animated slide-out delete
.removing class triggers @keyframes slideOut — slides right + collapses max-height to 0. State array updates in the animationend callback, keeping DOM and data in sync.
Done state with CSS transitions
Checking a task toggles .done-state: green checkbox fill, strikethrough text, light green card background — all CSS transitions, zero JS style changes.
Filter tabs (All / Active / Done)
Filter tabs clear and re-render the list without a full DOM teardown. New items get staggered delay; removed items animate out independently.
Live task counter
"X left" badge counts active tasks. Footer shows "X of Y complete". Both update on every state change — render() is the single source of truth.
Delete button on hover
Delete button has opacity: 0 by default; opacity: 1 on .task-item:hover. Keyboard users can tab to the button directly since it's always in the focus order.
Bulk "Clear done" action
The footer "Clear done" button calls deleteTask on each completed item — each one gets its own slide-out animation independently.
ARIA live region
The <ul aria-live="polite"> announces additions and deletions to screen readers without interrupting ongoing speech.

About this UI Snippet

Animated Task List — Slide-In/Out Keyframes, Filter Tabs & Optimistic State Update

Screenshot of the Animated Task List snippet rendered live

Animated lists are a foundational interaction pattern in modern web apps — tasks that slide in when added, check off with a strikethrough, and slide out when deleted make state changes feel tangible rather than instantaneous. This snippet builds a complete animated task manager: a slide-in @keyframes for new items, a CSS transition for done state (strikethrough + green border), a slide-out animation on delete, filter tabs (All / Active / Done), a live "tasks left" counter, and a "Clear done" bulk action — all in plain HTML, CSS, and vanilla JavaScript.

Animation patterns for lists are tricky because adding, removing, and updating items need separate animation strategies that coexist without flickering.

Slide-in animation for new tasks

New items use animation: slideIn .28s cubic-bezier(.34,1.56,.64,1) — a spring-overshoot easing that gives the item a slight bounce on entry. The translateY(-12px) scale(.97) start state gives the impression of the item dropping in from slightly above. When multiple items are shown (e.g., on filter change), each gets a staggered animation-delay of i * 30ms — a ripple cascade that makes the full list feel alive.

Slide-out animation on delete

Rather than immediately removing the DOM element, the delete handler adds a .removing class and listens for animationend. The animation slides the item right and collapses its height: transform: translateX(20px) scale(.96), opacity: 0, max-height: 0, padding: 0. Transitioning max-height to 0 smoothly closes the gap in the list without a jump. Crucially, the actual state array (tasks.filter) runs after the animation completes — the DOM removal and state removal are in sync.

Filter tabs without full re-render

The filter buttons switch the filter variable and clear the list, then call render(). The render function computes which items should be visible and adds only the ones not already in the DOM — an incremental DOM approach. Items that were removed by filter change are handled by the "remove deleted items" loop that also runs on each render pass. This prevents flicker from a full list teardown on every filter switch.

Live counter with ARIA live region

The <ul> has aria-live="polite" — screen readers announce additions and removals. The count badge reads "X left" (active task count) and the footer shows "X of Y complete" — two levels of progress feedback. Pair with a progress bar if you want a visual completion percentage bar across the top.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA task list card renders with four pre-loaded tasks, filter tabs, an add input, and a footer with completion stats.
  2. 2
    Type a task and press EnterThe new task slides in from above with a spring bounce animation. The counter updates immediately.
  3. 3
    Click the checkbox to complete a taskThe checkbox fills green, the text gets a strikethrough and turns grey, and the card background turns light green — all via CSS class toggle.
  4. 4
    Hover and click the delete buttonThe × button appears on hover. Clicking it slides the item to the right and collapses its height before removing it from the DOM.
  5. 5
    Use the filter tabs"Active" shows only incomplete tasks. "Done" shows only completed tasks. "All" shows everything. The list re-renders with a staggered slide-in for visible items.
  6. 6
    Click "Clear done"All completed tasks animate out simultaneously. The counter and footer stats update after all animations complete.

Real-world uses

Common Use Cases

Todo apps and task managers
The canonical use case — a personal or project task list with completion tracking. Extend with categories, priorities, and due dates for a full task management interface.
Shopping cart item lists
Items animate in when added to cart and animate out when removed. The spring entry gives physical weight to the add action — higher conversion than a silent counter increment.
Feature checklist / onboarding steps
A setup wizard where each completed step checks off with animation. The "tasks left" counter shows onboarding progress without a separate progress bar.
Notification and inbox management
Each notification slides in when received and slides out when dismissed. The "Clear done" pattern maps to "Mark all as read". Pair with a notification center.
Kanban column item lists
Each kanban column is an animated list. Items animate when moved between columns (add to target, remove from source with matching animations). Pair with the kanban board snippet.
Reading list or watchlist
Bookmark items animate in on save and strikethrough when read/watched. Filter tabs become "Unread / Read / All" — the same pattern maps directly.
Related: Anime.js SVG Shape Morph
See the Anime.js SVG Shape Morph for a related animations pattern worth pairing with this one.
Related: Circular Reveal Theme Toggle (View Transitions API)
See the Circular Reveal Theme Toggle (View Transitions API) for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

On every state change, call localStorage.setItem('tasks', JSON.stringify(tasks)). On load, initialise: let tasks = JSON.parse(localStorage.getItem('tasks') || 'null') || defaultTasks.

Add draggable="true" to each .task-item. Use dragstart, dragover, and drop events to track the dragged item and its target. On drop, splice the tasks array and call render(). For a polished version, see the drag sort list snippet.

Add a dueDate property to each task object. Render it as a <time> element inside the list item. Add a date picker input to the add form. Highlight overdue tasks with a red background by comparing task.dueDate < new Date().toISOString().

Use useState for the tasks array. The add handler calls setTasks(prev => [newTask, ...prev]). Toggle done: setTasks(prev => prev.map(t => t.id === id ? {...t, done: !t.done} : t)). Delete: setTasks(prev => prev.filter(t => t.id !== id)). CSS animations still trigger because the DOM element is newly mounted on each add.