UIPackage
Menu

Framework

Change language

Boilerplate repo

Onboarding Checklist

blockauth

Progressive activation checklist card: header with title, an N of M complete counter and a linear Progress bar, tappable task rows with icon tiles, one-line descriptions and chevrons (completed tasks flip to a filled check tile with muted copy), a footer with a Skip for now ghost link and an X dismiss that fades the card out, and a success panel with a glowing check circle at 5 of 5. State is local — wire tasks to your own activation API.

Also available for Vue ->

Installation

$npx shadcn@latest add https://uipkge.dev/r/react/onboarding-checklist.json
Named registry:npx shadcn@latest add @uipkge-react/onboarding-checklistInstalls to:components/blocks/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
initialComplete

Seed every task as done so the success panel can be previewed in isolation.

booleanoptional
classNamestringoptional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

Task
interface Task {
  id: string
  title: string
  description: string
  icon: LucideIcon
}

npm dependencies

Files installed (1)

  • components/blocks/OnboardingChecklist.tsx6.3 kB
    'use client'
    
    import * as React from 'react'
    import { Bell, BookOpen, Building2, Check, ChevronRight, Database, Users, X } from 'lucide-react'
    import type { LucideIcon } from 'lucide-react'
    import { cn } from '@/lib/utils'
    import { Button } from '@/components/ui/button'
    import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
    import { Progress } from '@/components/ui/progress'
    
    interface Task {
      id: string
      title: string
      description: string
      icon: LucideIcon
    }
    
    const baseTasks: Task[] = [
      {
        id: 'workspace',
        title: 'Create workspace',
        description: 'Name your team space and pick a URL.',
        icon: Building2,
      },
      {
        id: 'teammates',
        title: 'Invite teammates',
        description: 'Bring in the people you work with.',
        icon: Users,
      },
      {
        id: 'data',
        title: 'Connect your data',
        description: 'Sync sources so insights flow in automatically.',
        icon: Database,
      },
      {
        id: 'alerts',
        title: 'Set up alerts',
        description: 'Get notified when metrics move.',
        icon: Bell,
      },
      {
        id: 'api',
        title: 'Explore API docs',
        description: 'Learn the endpoints and ship your first request.',
        icon: BookOpen,
      },
    ]
    
    export interface OnboardingChecklistProps {
      /** Seed every task as done so the success panel can be previewed in isolation. */
      initialComplete?: boolean
      className?: string
    }
    
    export function OnboardingChecklist({ initialComplete = false, className }: OnboardingChecklistProps) {
      const [tasks, setTasks] = React.useState(() =>
        baseTasks.map((task, index) => ({ ...task, done: initialComplete || index < 3 })),
      )
      const [open, setOpen] = React.useState(true)
    
      const completed = tasks.filter((task) => task.done).length
      const total = tasks.length
      const percent = Math.round((completed / total) * 100)
      const allDone = completed === total
    
      function toggle(id: string) {
        setTasks((prev) => prev.map((task) => (task.id === id ? { ...task, done: !task.done } : task)))
      }
    
      return (
        <div
          data-slot="onboarding-checklist"
          className={cn(
            'mx-auto w-full max-w-md transition-[opacity,translate] duration-200 ease-out motion-reduce:transition-none',
            !open && 'pointer-events-none translate-y-1 opacity-0',
            className,
          )}
        >
          <Card>
            <CardHeader>
              <CardTitle>Get started</CardTitle>
              <CardDescription>Finish these steps to unlock everything your workspace can do.</CardDescription>
            </CardHeader>
            <CardContent className="space-y-4">
              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <p className="text-muted-foreground text-xs">
                    <span className="text-foreground font-medium">
                      {completed} of {total}
                    </span>{' '}
                    complete
                  </p>
                  <p className="text-muted-foreground text-xs tabular-nums">{percent}%</p>
                </div>
                <Progress value={percent} />
              </div>
    
              {allDone ? (
                <div className="space-y-4 py-6 text-center">
                  <div className="border-success/30 bg-success/10 text-success mx-auto flex size-16 items-center justify-center rounded-full border shadow-xs">
                    <Check className="size-8" aria-hidden="true" />
                  </div>
                  <div>
                    <p className="text-lg font-semibold">You're all set</p>
                    <p className="text-muted-foreground mt-1 text-sm">
                      Every step is complete — your workspace is ready to go.
                    </p>
                  </div>
                </div>
              ) : (
                <div className="-mx-2 divide-y">
                  {tasks.map((task) => {
                    const Icon = task.icon
                    return (
                      <button
                        key={task.id}
                        type="button"
                        role="checkbox"
                        aria-checked={task.done}
                        onClick={() => toggle(task.id)}
                        className="group hover:bg-muted/50 focus-visible:ring-ring flex w-full items-center gap-3 rounded-lg p-3 text-left transition-colors focus-visible:ring-2 focus-visible:outline-none"
                      >
                        {task.done ? (
                          <span className="bg-primary text-primary-foreground flex size-9 shrink-0 items-center justify-center rounded-md shadow-xs">
                            <Check className="size-4" aria-hidden="true" />
                          </span>
                        ) : (
                          <span className="border-border bg-muted text-muted-foreground group-hover:bg-background group-hover:text-foreground flex size-9 shrink-0 items-center justify-center rounded-md border transition-colors">
                            <Icon className="size-4" aria-hidden="true" />
                          </span>
                        )}
                        <span className="min-w-0 flex-1">
                          <span className={cn('block truncate text-sm font-medium', task.done && 'text-muted-foreground')}>
                            {task.title}
                          </span>
                          <span className="text-muted-foreground mt-0.5 block truncate text-xs">{task.description}</span>
                        </span>
                        <ChevronRight
                          className="text-muted-foreground/50 size-4 shrink-0 transition-transform duration-200 group-hover:translate-x-0.5"
                          aria-hidden="true"
                        />
                      </button>
                    )
                  })}
                </div>
              )}
            </CardContent>
            <CardFooter className="justify-between">
              {!allDone ? (
                <Button variant="ghost" size="sm" onClick={() => setOpen(false)}>
                  Skip for now
                </Button>
              ) : (
                <span aria-hidden="true" />
              )}
              <button
                type="button"
                aria-label="Dismiss checklist"
                onClick={() => setOpen(false)}
                className="hover:bg-foreground/10 focus-visible:ring-ring rounded-md p-1.5 transition-colors focus-visible:ring-2 focus-visible:outline-none"
              >
                <X className="text-muted-foreground size-4" aria-hidden="true" />
              </button>
            </CardFooter>
          </Card>
        </div>
      )
    }
    

Raw manifest:https://uipkge.dev/r/react/onboarding-checklist.json