# Task completed check

> Tap a task and the circle fills with a check while a line crosses out the text, both in one motion.

- Category: [Microinteractions](https://library.aimran.es/components/microinteractions)
- Built with: React + Motion
- Live editor: https://library.aimran.es/blocks/animated-task-check
- Library: AIMRAN Library (https://library.aimran.es), free, no sign-up, by Aimran Oukham

## Where to use it

Ticking something off a list should feel a little rewarding. Here the check pops in and the strike-through draws across the task at the same moment. It fits a to-do app, a travel packing list, an onboarding checklist or a wedding planner. A small animated checkbox like this makes people want to come back to the list.

Green reads as “done” almost everywhere, but your brand color works if it has enough contrast with the white check. Tapping again undoes the task, so keep that in mind if completed items move to another list.

## Code

### React (Motion)

```tsx
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Check } from "lucide-react";

const spring = { type: "spring" as const, stiffness: 300, damping: 30 };

interface TaskCheckProps {
  text?: string;
  color?: string;
}

export default function TaskCheck({
  text = "Pack for the trip",
  color = "#34c759",
}: TaskCheckProps) {
  const [done, setDone] = useState(false);

  return (
    <button
      type="button"
      aria-pressed={done}
      onClick={() => setDone((d) => !d)}
      className="flex items-center gap-3 rounded-2xl bg-white dark:bg-[#1c1c1e] px-5 py-4 text-[#1d1d1f] dark:text-[#f5f5f7] shadow-[0_1px_2px_rgba(0,0,0,0.03),0_8px_28px_rgba(0,0,0,0.05)]"
    >
      {/* --check-bg es el color de la tarjeta: el círculo se funde con ella cuando está vacío */}
      <motion.span
        animate={{ backgroundColor: done ? color : "var(--check-bg)" }}
        className="grid h-6 w-6 place-items-center rounded-full border border-black/10 [--check-bg:#ffffff] dark:border-white/10 dark:[--check-bg:#1c1c1e]"
      >
        <AnimatePresence>
          {done && (
            <motion.span initial={{ scale: 0 }} animate={{ scale: 1 }} exit={{ scale: 0 }} transition={spring}>
              <Check className="h-4 w-4 text-white" />
            </motion.span>
          )}
        </AnimatePresence>
      </motion.span>
      <span className="relative text-sm">
        <span>{text}</span>
        <motion.i
          className="absolute left-0 top-1/2 h-px bg-[#1d1d1f] dark:bg-[#f5f5f7]"
          animate={{ width: done ? "100%" : "0%" }}
          transition={spring}
        />
      </span>
    </button>
  );
}
```

## Prompt for AI assistants

Paste this into ChatGPT, Claude, Cursor, v0 or Lovable to adapt the block to your stack (Tailwind, Vue, Svelte…):

````text
I want to add the “Task completed check” block (Microinteractions) from AIMRAN Library to my project.

## What it is
Tap a task and the circle fills with a check while a line crosses out the text, both in one motion.

## Chosen settings
- Task: "Pack for the trip"
- Color: #34c759

## What I need
1. Add it to my project with the same look and animation as the reference code: same sizes, colours, radii, shadows, timings and easing.
2. It is built with React + TypeScript, with framer-motion for the animation and lucide-react for the icons. If my project uses something else (Vue, Svelte, Astro, plain HTML…), translate it without losing any behaviour. If I use Tailwind, turn the styles into classes; if not, keep the CSS in its own file.
3. Expose the settings above as props (or CSS variables) with those values as defaults.
4. Make it work well on phones: nothing that depends only on hover, touch targets of at least 44 px and no overflow on 320 px screens.
5. Make it look right in light and dark mode.
6. Keep it accessible: semantic HTML, roles and aria-* where needed, visible focus and keyboard support.
7. Respect prefers-reduced-motion: with reduced motion, no big animations but the same end result.

## Reference code
```tsx
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Check } from "lucide-react";

const spring = { type: "spring" as const, stiffness: 300, damping: 30 };

interface TaskCheckProps {
  text?: string;
  color?: string;
}

export default function TaskCheck({
  text = "Pack for the trip",
  color = "#34c759",
}: TaskCheckProps) {
  const [done, setDone] = useState(false);

  return (
    <button
      type="button"
      aria-pressed={done}
      onClick={() => setDone((d) => !d)}
      className="flex items-center gap-3 rounded-2xl bg-white dark:bg-[#1c1c1e] px-5 py-4 text-[#1d1d1f] dark:text-[#f5f5f7] shadow-[0_1px_2px_rgba(0,0,0,0.03),0_8px_28px_rgba(0,0,0,0.05)]"
    >
      {/* --check-bg es el color de la tarjeta: el círculo se funde con ella cuando está vacío */}
      <motion.span
        animate={{ backgroundColor: done ? color : "var(--check-bg)" }}
        className="grid h-6 w-6 place-items-center rounded-full border border-black/10 [--check-bg:#ffffff] dark:border-white/10 dark:[--check-bg:#1c1c1e]"
      >
        <AnimatePresence>
          {done && (
            <motion.span initial={{ scale: 0 }} animate={{ scale: 1 }} exit={{ scale: 0 }} transition={spring}>
              <Check className="h-4 w-4 text-white" />
            </motion.span>
          )}
        </AnimatePresence>
      </motion.span>
      <span className="relative text-sm">
        <span>{text}</span>
        <motion.i
          className="absolute left-0 top-1/2 h-px bg-[#1d1d1f] dark:bg-[#f5f5f7]"
          animate={{ width: done ? "100%" : "0%" }}
          transition={spring}
        />
      </span>
    </button>
  );
}
```

Give me the complete final code, ready to paste, and tell me in one line where to put it in my project.
````
