Source Code

<div class="sc-card" id="scCard">
  <button class="sc-header" id="scHeader" aria-expanded="true">
    <div class="sc-header-left">
      <svg class="sc-ring" width="44" height="44" viewBox="0 0 44 44">
        <circle class="sc-ring-track" cx="22" cy="22" r="18"></circle>
        <circle class="sc-ring-fill" id="scRingFill" cx="22" cy="22" r="18"></circle>
      </svg>
      <div>
        <h3>Get started</h3>
        <p id="scProgressText">0 of 5 complete</p>
      </div>
    </div>
    <svg class="sc-chevron" id="scChevron" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>
  </button>

  <div class="sc-body" id="scBody">
    <div class="sc-progress-bar"><div class="sc-progress-fill" id="scProgressFill"></div></div>
    <ul class="sc-list" id="scList"></ul>
  </div>
</div>

Setup Checklist Onboarding Widget — Free HTML CSS JS Snippet

Setup Checklist Onboarding Widget · Dashboards · Plain HTML, CSS & JS · Live preview

What's included

Features

Single TASKS array as the source of truth for the checklist, progress bar, and progress ring
SVG circular progress ring animated via stroke-dasharray/stroke-dashoffset, no canvas or library
Linear progress bar and "X of Y complete" text kept perfectly in sync with the ring
Click-to-toggle checklist rows with checkmark and strikethrough styling on completion
Collapsible card body with a smooth height/opacity transition and rotating chevron
Live recomputed completed-count state on every toggle, not a static percentage
Fully keyboard-accessible header button with aria-expanded state
Self-contained card styling that drops into any dashboard or sidebar

About this UI Snippet

Setup Checklist Onboarding Widget — Collapsible Progress Ring Checklist

Screenshot of the Setup Checklist Onboarding Widget snippet rendered live

New users rarely finish setup on their own, so many products surface a persistent "Get started" widget that tracks completion of a handful of onboarding tasks and nudges the user toward finishing them. This snippet implements that pattern as a single card: a circular progress ring plus a linear progress bar, and a five-item checklist that can be toggled complete by clicking any row.

One state array drives every visual

A plain TASKS array of { id, label, done } objects is the entire source of truth. renderList() builds the checklist rows from it, and renderProgress() recomputes the completed count, the linear progress bar's width, and the ring's stroke offset — all three visuals are derived, never set independently, so they can never disagree with each other.

The progress ring without a library

The ring is a pair of concentric SVG <circle> elements. The foreground circle's stroke-dasharray is fixed to its full circumference; its stroke-dashoffset is set to circumference * (1 - completedFraction), which visually "fills in" the ring proportionally to progress, animated with a CSS transition on stroke-dashoffset.

Toggling and collapsing

Clicking any checklist row flips that task's done flag and re-renders both the list and the progress visuals — there is no separate "mark complete" button, keeping the interaction to a single click per task. The header itself is a button that toggles a .sc-collapsed class on the card, collapsing the body via a max-height/opacity transition and rotating the chevron, so the widget can be tucked away without losing its progress state.

Step by step

How to Use

  1. 1
    Load the snippetClick "Setup Checklist Onboarding Widget" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
  2. 2
    Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
  3. 3
    Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
  4. 4
    Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
  5. 5
    Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.

Real-world uses

Common Use Cases

Product onboarding dashboards
Surface a persistent setup checklist on a new user's dashboard home screen.
SaaS activation flows
Nudge free-trial users toward the setup steps most correlated with retention.
Account setup wizards
Track completion of profile, security, and integration setup steps in one widget.
Teaching derived UI state
A clear example of computing multiple visuals from one shared state array.

Got questions?

Frequently Asked Questions

It is two SVG circles. The foreground circle's stroke-dasharray equals its full circumference, and its stroke-dashoffset is set to circumference times (1 minus the completed fraction), which visually reveals more of the stroke as progress increases.

All three are recalculated from the same TASKS array inside renderProgress(), which runs after every toggle. There is no independent state for any of the three visuals.

The row's done flag flips, both renderList() and renderProgress() re-run, and the row gets a filled checkmark and strikethrough label while the ring and bar animate to the new percentage.

Yes — clicking a completed row toggles it back to incomplete, and all three progress visuals update accordingly.