Componentdata1.04 KB gzipZero dependencies
Task List
Task rows with assignee chips and priority badges.
Preview
Live Preview
- Print posterAL
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add task-listOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { TaskList } from "@/components/ui/task-list";
<TaskList />Usage guidance
Use Task List when a ticket stub surface needs Task rows with assignee chips and priority badges. Keep props minimal and prefer composition with sibling stubs.
Avoid Task List for long form flows or dense data grids where a dedicated layout block fits better.
Source code
task-list.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface TaskListProps extends Omit<React.HTMLAttributes<HTMLUListElement>, "onToggle"> {
tasks: { id: string; label: string; assignee?: string; priority?: "low" | "med" | "high"; done?: boolean }[];
onToggle?: (id: string) => void;
}
const PRI: Record<string, string> = { low: "text-muted-foreground", med: "text-warning", high: "text-destructive" };
/** Task list item rows: assignee chip + priority dot indicator. */
export function TaskList({ tasks, onToggle, className, ...props }: TaskListProps) {
const [state, setState] = React.useState(tasks);
React.useEffect(() => setState(tasks), [tasks]);
return (
<ul className={cn("w-full max-w-sm space-y-1", className)} {...props}>
<style>{`@keyframes tlIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }`}</style>
{state.map((t, idx) => (
<li
key={t.id}
className="flex items-center gap-2.5 rounded-md border border-border bg-card px-3 py-2 animate-[tlIn_0.25s_ease-out_both] motion-reduce:animate-none transition-colors hover:border-foreground/30 motion-reduce:transition-none"
style={{ animationDelay: `${idx * 40}ms` }}
>
<input
type="checkbox"
checked={t.done}
onChange={() => { setState((s) => s.map((x) => (x.id === t.id ? { ...x, done: !x.done } : x))); onToggle?.(t.id); }}
className="size-3.5 shrink-0 accent-accent"
aria-label={t.label}
/>
<span className={cn("min-w-0 flex-1 truncate text-sm transition-colors motion-reduce:transition-none", t.done && "text-muted-foreground line-through")}>{t.label}</span>
{t.assignee && <span className="shrink-0 rounded-full bg-secondary px-1.5 py-px font-mono text-[9px] text-secondary-foreground">{t.assignee}</span>}
{t.priority && <span className={cn("size-1.5 shrink-0 rounded-full", t.priority === "high" ? "bg-destructive" : t.priority === "med" ? "bg-warning" : "bg-border")} aria-label={t.priority} />}
</li>
))}
</ul>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| tasks | { id: string; label: string; assignee?: string; priority?: "low" | "med" | "high"; done?: boolean }[] | |
| onToggle | (id: string) => void |