# JoyfulTaskCheckbox

> A task checkbox with a small, restrained completion moment: one soft bloom, two sparks, then stillness.

## Facts

- **Product**: Max
- **Family**: Motion
- **Global**: `window.DigitalCrew.JoyfulTaskCheckbox`
- **Source**: `max-agent: src/features/tasks/ui/joyful-task-checkbox.tsx`
- **Import in the app**: `import { JoyfulTaskCheckbox } from "@/features/tasks/ui/joyful-task-checkbox";`
- **Live preview**: /design/components/joyful-task-checkbox/preview.html
- **Page**: /design/components/joyful-task-checkbox

## Guidelines

Tasks and Pipeline both use it.

**Use it for** completing a task, a one-way action. It checks at once and asks you to confirm the write.

**What you provide**
- `checked` and `label`, which is the accessible name.
- `onComplete()`, which returns `Promise<boolean>`. Resolve `false` if the write was refused and the control settles back to idle.
- Optional: `disabled` (default false), `disabledReason` (shown as a title and an `aria-description`) and `className`.

**Anatomy**
- A `size-6` box with a `rounded-[6px]`, `border-2 border-foreground/65` edge on `bg-background`. Hover gives `border-foreground bg-muted/60`.
- Checked: `border-emerald-500 bg-emerald-500 text-white`.
- Disabled: `border-foreground/45 bg-muted/30` at full opacity.
- The hit area extends 10px beyond the box (`after:-inset-2.5`), and focus shows a 2px ring with a 2px offset.

**Motion** (CSS, while the write is pending)
- `task-complete-pop`: scale 0.82 to 1.18 to 1 over 360ms, `cubic-bezier(0.22, 1, 0.36, 1)`.
- A halo in `border-emerald-400/70` grows from 0.75 to 2.35 and fades out over 520ms ease-out.
- Two 4px sparks: `emerald-400` flies up-left (480ms) and `amber-300` up-right (520ms, 35ms delay).
- The check mark turns in from scale 0.55 and −8° over 240ms.
- `prefers-reduced-motion` turns all of it off. It is still a real, labelled checkbox to assistive technology.

**Don't** use it for settings or anything that can be unchecked (a checked box is disabled), and don't add confetti on top.

## API

```ts
interface JoyfulTaskCheckboxProps {
    checked: boolean;
    disabled?: boolean;
    disabledReason?: string;
    label: string;
    className?: string;
    /**
     * Return false when the write was refused. The control then settles back to
     * its idle state instead of leaving an optimistic check on screen.
     */
    onComplete(): Promise<boolean>;
}
/**
 * A restrained completion moment shared by Tasks and Pipeline.
 *
 * The check fills immediately so the click feels responsive, then the caller
 * confirms whether the canonical task write succeeded. Motion is CSS-only and
 * disappears under prefers-reduced-motion; the control remains a real,
 * labelled checkbox to assistive technology.
 */
export declare function JoyfulTaskCheckbox({ checked, disabled, disabledReason, label, className, onComplete, }: JoyfulTaskCheckboxProps): JSX.Element;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  var TASKS = [
    { id: "t1", title: "Send Claire Dubois the Thursday call agenda", meta: "Due today · Northwind Traders" },
    { id: "t2", title: "Log the discovery call with Marcus Reinholt", meta: "Due today · Brightline Logistics" },
    { id: "t3", title: "Follow up on the Brightline pilot proposal", meta: "Due Fri · Tomás Alvarez" }
  ];
  function App() {
    var d = React.useState({}), done = d[0], setDone = d[1];
    var k = React.useState(0), round = k[0], setRound = k[1];
    function completer(id) {
      return function () {
        return new Promise(function (resolve) {
          setTimeout(function () {
            setDone(function (x) { var n = Object.assign({}, x); n[id] = true; return n; });
            resolve(true);
          }, 700);
        });
      };
    }
    React.useEffect(function () {
      // Complete two tasks on their own so the burst plays without a click
      // (the second lands where a still capture at ~1.5s catches it mid-bloom).
      function tick(id) {
        var box = document.querySelector('[data-auto="' + id + '"] button[role="checkbox"]');
        if (box) box.click();
      }
      var a = setTimeout(function () { tick("t2"); }, 600);
      var b = setTimeout(function () { tick("t3"); }, 1350);
      return function () { clearTimeout(a); clearTimeout(b); };
    }, [round]);
    var count = Object.keys(done).length;
    return h("div", { className: "mx-auto max-w-[520px] rounded-2xl border border-border/60 bg-card p-2 shadow-sm" },
      h("div", { className: "flex items-center justify-between px-3 pb-1 pt-2" },
        h("span", { className: "text-sm font-semibold" }, "Today"),
        h("button", { type: "button", className: "text-xs text-muted-foreground hover:text-foreground",
          onClick: function () { setDone({}); setRound(round + 1); } }, count + " of 3 done · reset")),
      TASKS.map(function (t) {
        var checked = !!done[t.id];
        return h("div", { key: t.id + round, "data-auto": t.id, className: "flex items-center gap-3 rounded-xl px-3 py-2.5 hover:bg-muted/40" },
          h(DC.JoyfulTaskCheckbox, { checked: checked, label: "Complete: " + t.title, onComplete: completer(t.id) }),
          h("div", { className: "min-w-0 flex-1" },
            h("div", { className: "truncate text-sm font-medium transition-colors " + (checked ? "text-muted-foreground line-through" : "") }, t.title),
            h("div", { className: "text-xs text-muted-foreground" }, t.meta)));
      }));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Motion

- [ActionFocusSession](/design/components/action-focus-session.md): The focus timebox for one task in the actions cockpit: a live billable clock with approve, start, pause, run and done, and a burst of sparkles on completion.
- [CardResize](/design/components/card-resize.md): A container that tweens its width and height when its content changes (`.t-resize`).
- [ChapterScrubber](/design/components/chapter-scrubber.md): A rail of ticks, one per chapter, that swell like a dock under the pointer, with a card previewing the hovered chapter.
- [ContainerScroll](/design/components/container-scroll.md): A hero block where a device-like frame starts tilted back in 3D and straightens as the page scrolls, with the title drifting up.
- [FeatureSlideshow](/design/components/feature-slideshow.md): A step-by-step feature explainer: an accordion of steps on the left that advances on a timer, a progress line on the open step, and a large media slot on the right.
- [FirstBentoAnimation](/design/components/first-bento-animation.md): A self-playing chat vignette for the bento grid: a user asks for a meeting slot, the Digital Crew avatar shows typing dots, then the reply streams in as a `Reasoning` block.
- [FourthBentoAnimation](/design/components/fourth-bento-animation.md): A scheduling vignette for the bento grid: a week ruler, three task bars that spring into place, and a time cursor that follows the pointer.
- [HyperText](/design/components/hyper-text.md): A monospaced, uppercase text effect: letters scramble through random characters, then lock in from left to right.
- [InfiniteSlider](/design/components/infinite-slider.md): A JavaScript-driven endless strip (Framer Motion) that renders its children twice and slides them in a loop, optionally slowing on hover.
- [Lottie](/design/components/lottie.md): The lottie-react player, exported as-is, for the Lottie animations that ship with Crew OS (`animations/*.json`).
- [Marquee](/design/components/marquee.md): An endless CSS scroll of repeated content, horizontal or vertical, speed set with two CSS variables.
- [MotionScale](/design/components/motion-scale.md): The shared motion scale made visible: the same distance travelled on each duration token and each easing, with a Replay button.
- [NumberFlowCounter](/design/components/number-flow-counter.md): A small dark pill that shows one number at a time and rolls its digits to the next value every two seconds (NumberFlow).
- [OrbitingCircles](/design/components/orbiting-circles.md): Places its children on a circular orbit around the centre of the parent and spins them, with an optional faint ring for the path.
- [ShimmerText](/design/components/shimmer-text.md): A status line with a light band sweeping across its glyphs — Max's "Thinking…" and live tool lines (`.t-shimmer`).
- [SignatureGradient](/design/components/signature-gradient.md): The signature Digital Crew gradient — indigo → pink → amber (`dc-andre`, `dc-camille`, `dc-amber`) — in its four forms.
- [SkeletonReveal](/design/components/skeleton-reveal.md): A skeleton that cross-blurs into the loaded content, so the swap reads as one motion (`.t-skel`).
- [StreamingText](/design/components/streaming-text.md): Streamed words resolving through a soft cross-blur, one after another (`.t-stream-w` → `.is-in`).
- [ThirdBentoAnimation](/design/components/third-bento-animation.md): An insight vignette for the bento grid: a smooth area line draws itself, a dot pulses at its midpoint and a dark pill above it ticks through values.
- [UniboxMotion](/design/components/unibox-motion.md): The Unibox's shared motion vocabulary: every surface moves on the same few springs, so the whole inbox feels like one physical material.
