Open demo

CSS code

HTML
<div><span class="lbl">Filters and counts with :has() and CSS counters</span>
<section class="mc" aria-labelledby="garden-title">
  <div class="mc-head"><h2 id="garden-title">Garden weekend</h2>
    <fieldset class="mc-filter"><legend class="sr-only">Show tasks</legend><label class="mc-seg"><input type="radio" name="garden-show" value="all" checked><span>All</span></label><label class="mc-seg"><input type="radio" name="garden-show" value="active"><span>To do</span></label><label class="mc-seg"><input type="radio" name="garden-show" value="done"><span>Done</span></label></fieldset></div>
  <ul class="mc-list" aria-label="Garden tasks">
    <li class="mc-item"><input class="mc-box" type="checkbox" id="garden-1" data-task checked><label for="garden-1">Mow the back lawn</label></li>
    <li class="mc-item"><input class="mc-box" type="checkbox" id="garden-2" data-task><label for="garden-2">Plant the tulip bulbs along the fence</label></li>
    <li class="mc-item"><input class="mc-box" type="checkbox" id="garden-3" data-task><label for="garden-3">Fix the latch on the side gate</label></li>
    <li class="mc-item"><input class="mc-box" type="checkbox" id="garden-4" data-task checked><label for="garden-4">Clean out the bird bath</label></li>
    <li class="mc-item"><input class="mc-box" type="checkbox" id="garden-5" data-task><label for="garden-5">Take the green waste to the tip</label></li>
  </ul>
  <p class="mc-empty is-done">Nothing ticked off yet.</p>
  <p class="mc-empty is-active">Everything on this list is done.</p>
  <p class="mc-foot"><span class="mc-left"></span> to do<span aria-hidden="true"> · </span><span class="mc-done"></span> done<span class="mc-all"> · All finished, enjoy the garden</span></p>
</section></div>

<div><span class="lbl">Hide completed, native checkboxes, growing notes</span>
<section class="mc club" aria-labelledby="club-title">
  <div class="mc-head"><div><h2 id="club-title">Book club at mine</h2><p class="mc-sub">Friday 19:30 · <cite>The Lighthouse Keeper’s Daughter</cite></p></div>
    <label class="mc-switch"><input type="checkbox" role="switch" data-hide><span>Hide completed</span></label></div>
  <ul class="mc-clist" aria-label="Book club tasks">
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-1" data-task checked><label for="club-1">Buy two bottles of white wine</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-2" data-task><label for="club-2">Bake the lemon drizzle cake</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-3" data-task checked><label for="club-3">Print the discussion questions</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-4" data-task><label for="club-4">Borrow four extra chairs from Ana</label></li>
  </ul>
  <p class="mc-hidden-note">Completed tasks are hidden.</p>
  <label class="mc-nlabel" for="club-notes">Notes for the evening</label>
  <textarea class="mc-notes" id="club-notes" rows="2">Ana arrives early to help set up.
Tom is bringing the vegan option.</textarea>
  <p class="mc-nhint">The field grows as you type, up to ten lines.</p>
</section></div>
CSS
/* Modern CSS to-do lists, no JavaScript. :has() on the card reads the filter radios and hides rows; hidden rows
   collapse with visibility:hidden instead of display:none so CSS counters still count them. The second card uses
   native checkboxes coloured with accent-color, a role="switch" checkbox that hides finished rows, and field-sizing. */
.mc{--mc-ink:#16173a;--mc-muted:#55587a;--mc-line:#e3e4f3;--mc-box:#7d80a6;--mc-accent:#4338ca;--mc-accent-dark:#3730a3;--mc-tint:#eceefc;
  counter-reset:left done;background:#fff;color:var(--mc-ink);border:1px solid var(--mc-line);border-radius:20px;padding:24px;box-shadow:0 20px 44px -30px rgba(22,23,58,.45)}
.mc :where(h2,p,ul,fieldset,legend){margin:0;padding:0}
.mc ul{list-style:none}
.mc-head{display:flex;align-items:center;justify-content:space-between;gap:12px 16px;flex-wrap:wrap}
.mc h2{font-size:1.2rem;font-weight:800;letter-spacing:-.015em}
.mc-sub{margin-top:3px!important;font-size:.85rem;color:var(--mc-muted)}
.mc-sub cite{font-style:italic}
/* filter radios */
.mc-filter{display:flex;gap:2px;padding:3px!important;border:0;border-radius:999px;background:var(--mc-tint);min-width:0}
.mc-seg{position:relative;cursor:pointer}
.mc-seg input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.mc-seg span{display:block;padding:6px 14px;border-radius:999px;font-size:.85rem;font-weight:650;color:var(--mc-muted);transition:background-color .15s,color .15s}
.mc-seg:hover span{color:var(--mc-ink)}
.mc-seg input:checked+span{background:#fff;color:var(--mc-ink);box-shadow:0 1px 3px rgba(22,23,58,.2)}
.mc-seg input:focus-visible+span{outline:3px solid var(--mc-accent);outline-offset:2px}
/* rows */
.mc-list{margin-top:14px!important;border-top:1px solid var(--mc-line)}
.mc-item{display:flex;align-items:center;gap:12px;padding:11px 4px;border-bottom:1px solid var(--mc-line);counter-increment:left}
.mc-item:has(:checked){counter-increment:done}
.mc-box{appearance:none;flex:none;width:22px;height:22px;margin:0;border:2px solid var(--mc-box);border-radius:7px;background:#fff center/14px no-repeat;cursor:pointer;transition:background-color .15s,border-color .15s}
.mc-box:checked{background-color:var(--mc-accent);border-color:var(--mc-accent);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E")}
.mc-box:focus-visible{outline:3px solid var(--mc-accent);outline-offset:2px}
.mc-item label{flex:1;min-width:0;font-size:1rem;line-height:1.4;cursor:pointer}
.mc-box:checked+label{color:var(--mc-muted);text-decoration:line-through}
.mc:has([value=active]:checked) .mc-item:has(:checked),
.mc:has([value=done]:checked) .mc-item:not(:has(:checked)){visibility:hidden;block-size:0;padding-block:0;border-width:0;overflow:hidden}
/* empty states and counts */
.mc-empty{display:none;padding:22px 8px!important;text-align:center;font-size:.95rem;color:var(--mc-muted)}
.mc:has([value=done]:checked):not(:has([data-task]:checked)) .mc-empty.is-done,
.mc:has([value=active]:checked):not(:has([data-task]:not(:checked))) .mc-empty.is-active{display:block}
.mc-foot{margin-top:14px!important;font-size:.88rem;font-weight:650;color:var(--mc-muted)}
.mc-left::before{content:counter(left)}
.mc-done::before{content:counter(done)}
.mc-all{display:none;color:var(--mc-accent-dark)}
.mc:not(:has([data-task]:not(:checked))) .mc-all{display:inline}
/* hide-completed switch */
.mc-switch{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:.88rem;font-weight:650;color:var(--mc-muted)}
.mc-switch input{appearance:none;flex:none;position:relative;width:38px;height:22px;margin:0;border-radius:999px;background:#7d80a6;cursor:pointer;transition:background-color .2s}
.mc-switch input::before{content:"";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:translate .2s}
.mc-switch input:checked{background:var(--mc-accent)}
.mc-switch input:checked::before{translate:16px 0}
.mc-switch input:focus-visible{outline:3px solid var(--mc-accent);outline-offset:2px}
.mc-clist{margin-top:14px!important;display:grid;gap:6px}
.mc-citem{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:12px;background:#f6f7fd;transition:background-color .15s}
.mc-citem:has(:checked){background:transparent;box-shadow:inset 0 0 0 1px var(--mc-line)}
.mc-native{flex:none;width:18px;height:18px;margin:0;accent-color:var(--mc-accent);cursor:pointer}
.mc-native:focus-visible{outline:3px solid var(--mc-accent);outline-offset:2px}
.mc-citem label{flex:1;min-width:0;font-size:.98rem;line-height:1.4;cursor:pointer}
.mc-native:checked+label{color:var(--mc-muted);text-decoration:line-through}
.mc.club:has([data-hide]:checked) .mc-citem:has(:checked){display:none}
.mc-hidden-note{display:none;margin-top:10px!important;font-size:.85rem;color:var(--mc-muted)}
.mc.club:has([data-hide]:checked):has(.mc-citem :checked) .mc-hidden-note{display:block}
/* field-sizing: the notes field grows with its content */
.mc-nlabel{display:block;margin-top:18px;font-size:.85rem;font-weight:700}
.mc-notes{display:block;width:100%;margin-top:6px;font:inherit;font-size:.95rem;line-height:1.5;padding:10px 12px;border:1.5px solid var(--mc-box);border-radius:12px;background:#fff;color:var(--mc-ink);resize:none;
  field-sizing:content;min-block-size:calc(3lh + 20px);max-block-size:calc(10lh + 20px)}
.mc-notes:focus{outline:3px solid var(--mc-accent);outline-offset:1px;border-color:var(--mc-accent)}
.mc-nhint{margin-top:6px!important;font-size:.8rem;color:var(--mc-muted)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
@media (max-width:480px){.mc{padding:20px 16px}}
@media (prefers-reduced-motion:reduce){.mc *,.mc *::before{transition:none!important}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Filters and counts with :has() and CSS counters</span>
<section class="card mc" aria-labelledby="garden-title">
  <div class="mc-head"><h2 id="garden-title">Garden weekend</h2>
    <fieldset class="mc-filter"><legend class="visually-hidden">Show tasks</legend><label class="mc-seg"><input class="btn-check" type="radio" name="garden-show" value="all" checked><span class="btn">All</span></label><label class="mc-seg"><input class="btn-check" type="radio" name="garden-show" value="active"><span class="btn">To do</span></label><label class="mc-seg"><input class="btn-check" type="radio" name="garden-show" value="done"><span class="btn">Done</span></label></fieldset></div>
  <ul class="mc-list" aria-label="Garden tasks">
    <li class="mc-item"><input class="form-check-input mc-box" type="checkbox" id="garden-1" data-task checked><label for="garden-1">Mow the back lawn</label></li>
    <li class="mc-item"><input class="form-check-input mc-box" type="checkbox" id="garden-2" data-task><label for="garden-2">Plant the tulip bulbs along the fence</label></li>
    <li class="mc-item"><input class="form-check-input mc-box" type="checkbox" id="garden-3" data-task><label for="garden-3">Fix the latch on the side gate</label></li>
    <li class="mc-item"><input class="form-check-input mc-box" type="checkbox" id="garden-4" data-task checked><label for="garden-4">Clean out the bird bath</label></li>
    <li class="mc-item"><input class="form-check-input mc-box" type="checkbox" id="garden-5" data-task><label for="garden-5">Take the green waste to the tip</label></li>
  </ul>
  <p class="mc-empty is-done">Nothing ticked off yet.</p>
  <p class="mc-empty is-active">Everything on this list is done.</p>
  <p class="mc-foot"><span class="mc-left"></span> to do<span aria-hidden="true"> · </span><span class="mc-done"></span> done<span class="mc-all"> · All finished, enjoy the garden</span></p>
</section></div>

<div><span class="lbl">Hide completed, native checkboxes, growing notes</span>
<section class="card mc club" aria-labelledby="club-title">
  <div class="mc-head"><div><h2 id="club-title">Book club at mine</h2><p class="mc-sub">Friday 19:30 · <cite>The Lighthouse Keeper’s Daughter</cite></p></div>
    <label class="form-check form-switch mc-switch"><input class="form-check-input" type="checkbox" role="switch" data-hide><span class="form-check-label">Hide completed</span></label></div>
  <ul class="mc-clist" aria-label="Book club tasks">
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-1" data-task checked><label for="club-1">Buy two bottles of white wine</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-2" data-task><label for="club-2">Bake the lemon drizzle cake</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-3" data-task checked><label for="club-3">Print the discussion questions</label></li>
    <li class="mc-citem"><input class="mc-native" type="checkbox" id="club-4" data-task><label for="club-4">Borrow four extra chairs from Ana</label></li>
  </ul>
  <p class="mc-hidden-note">Completed tasks are hidden.</p>
  <label class="form-label mc-nlabel" for="club-notes">Notes for the evening</label>
  <textarea class="form-control mc-notes" id="club-notes" rows="2">Ana arrives early to help set up.
Tom is bringing the vegan option.</textarea>
  <p class="mc-nhint">The field grows as you type, up to ten lines.</p>
</section></div>
CSS
/* Modern CSS to-do lists on Bootstrap, no JavaScript: .card, .btn-check + .btn, .form-check-input, .form-switch and .form-control. :has() on the card reads the filter radios and hides rows; hidden rows
   collapse with visibility:hidden instead of display:none so CSS counters still count them. The second card uses
   native checkboxes coloured with accent-color, a role="switch" checkbox that hides finished rows, and field-sizing. */
.mc{--bs-card-border-color:var(--mc-line);--bs-card-border-radius:20px;--mc-ink:#16173a;--mc-muted:#55587a;--mc-line:#e3e4f3;--mc-box:#7d80a6;--mc-accent:#4338ca;--mc-accent-dark:#3730a3;--mc-tint:#eceefc;
  counter-reset:left done;background:#fff;color:var(--mc-ink);border:1px solid var(--mc-line);border-radius:20px;padding:24px;box-shadow:0 20px 44px -30px rgba(22,23,58,.45)}
.mc :where(h2,p,ul,fieldset,legend){margin:0;padding:0}
.mc .mc-item label,.mc .mc-citem label{margin:0}
.mc h2{line-height:normal}
.mc ul{list-style:none}
.mc-head{display:flex;align-items:center;justify-content:space-between;gap:12px 16px;flex-wrap:wrap}
.mc h2{font-size:1.2rem;font-weight:800;letter-spacing:-.015em}
.mc-sub{margin-top:3px!important;font-size:.85rem;color:var(--mc-muted)}
.mc-sub cite{font-style:italic}
/* filter radios */
.mc-filter{display:flex;gap:2px;padding:3px!important;border:0;border-radius:999px;background:var(--mc-tint);min-width:0}
.mc-seg{position:relative;cursor:pointer}
.mc-seg .btn{--bs-btn-padding-x:14px;--bs-btn-padding-y:6px;--bs-btn-font-size:.85rem;--bs-btn-font-weight:650;--bs-btn-line-height:normal;--bs-btn-border-width:0;--bs-btn-border-radius:999px;--bs-btn-color:var(--mc-muted);--bs-btn-hover-color:var(--mc-ink);--bs-btn-active-color:var(--mc-ink);display:block;transition:background-color .15s,color .15s}
.mc-seg .btn-check:checked+.btn{background:#fff;color:var(--mc-ink);box-shadow:0 1px 3px rgba(22,23,58,.2)}
.mc-seg .btn-check:focus-visible+.btn{box-shadow:none;outline:3px solid var(--mc-accent);outline-offset:2px}
/* rows */
.mc-list{margin-top:14px!important;border-top:1px solid var(--mc-line)}
.mc-item{display:flex;align-items:center;gap:12px;padding:11px 4px;border-bottom:1px solid var(--mc-line);counter-increment:left}
.mc-item:has(:checked){counter-increment:done}
.mc .mc-box{flex:none;width:22px;height:22px;margin:0;border:2px solid var(--mc-box);border-radius:7px;background-size:14px;cursor:pointer;transition:background-color .15s,border-color .15s}
.mc .form-check-input:checked{background-color:var(--mc-accent);border-color:var(--mc-accent)}
.mc .form-check-input:focus{box-shadow:none}
.mc .form-check-input:focus-visible{outline:3px solid var(--mc-accent);outline-offset:2px}
.mc-item label{flex:1;min-width:0;font-size:1rem;line-height:1.4;cursor:pointer}
.mc-box:checked+label{color:var(--mc-muted);text-decoration:line-through}
.mc:has([value=active]:checked) .mc-item:has(:checked),
.mc:has([value=done]:checked) .mc-item:not(:has(:checked)){visibility:hidden;block-size:0;padding-block:0;border-width:0;overflow:hidden}
/* empty states and counts */
.mc-empty{display:none;padding:22px 8px!important;text-align:center;font-size:.95rem;color:var(--mc-muted)}
.mc:has([value=done]:checked):not(:has([data-task]:checked)) .mc-empty.is-done,
.mc:has([value=active]:checked):not(:has([data-task]:not(:checked))) .mc-empty.is-active{display:block}
.mc-foot{margin-top:14px!important;font-size:.88rem;font-weight:650;color:var(--mc-muted)}
.mc-left::before{content:counter(left)}
.mc-done::before{content:counter(done)}
.mc-all{display:none;color:var(--mc-accent-dark)}
.mc:not(:has([data-task]:not(:checked))) .mc-all{display:inline}
/* hide-completed switch */
.mc-switch{display:inline-flex;align-items:center;gap:9px;min-height:0;margin:0;padding:0;cursor:pointer;font-size:.88rem;font-weight:650;color:var(--mc-muted)}
.mc-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
  float:none;flex:none;width:38px;height:22px;margin:0;border:0;background-color:#7d80a6;cursor:pointer}
.mc-switch .form-check-input:checked{background-color:var(--mc-accent)}
.mc-switch .form-check-label{cursor:pointer}
.mc-clist{margin-top:14px!important;display:grid;gap:6px}
.mc-citem{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:12px;background:#f6f7fd;transition:background-color .15s}
.mc-citem:has(:checked){background:transparent;box-shadow:inset 0 0 0 1px var(--mc-line)}
.mc-native{flex:none;width:18px;height:18px;margin:0;accent-color:var(--mc-accent);cursor:pointer}
.mc-native:focus-visible{outline:3px solid var(--mc-accent);outline-offset:2px}
.mc-citem label{flex:1;min-width:0;font-size:.98rem;line-height:1.4;cursor:pointer}
.mc-native:checked+label{color:var(--mc-muted);text-decoration:line-through}
.mc.club:has([data-hide]:checked) .mc-citem:has(:checked){display:none}
.mc-hidden-note{display:none;margin-top:10px!important;font-size:.85rem;color:var(--mc-muted)}
.mc.club:has([data-hide]:checked):has(.mc-citem :checked) .mc-hidden-note{display:block}
/* field-sizing: the notes field grows with its content */
.mc .mc-nlabel{display:block;margin:18px 0 0;font-size:.85rem;font-weight:700}
.mc .mc-notes{display:block;width:100%;margin-top:6px;box-shadow:none;font-size:.95rem;line-height:1.5;padding:10px 12px;border:1.5px solid var(--mc-box);border-radius:12px;background:#fff;color:var(--mc-ink);resize:none;
  field-sizing:content;min-block-size:calc(3lh + 20px);max-block-size:calc(10lh + 20px)}
.mc .mc-notes:focus{box-shadow:none;outline:3px solid var(--mc-accent);outline-offset:1px;border-color:var(--mc-accent)}
.mc-nhint{margin-top:6px!important;font-size:.8rem;color:var(--mc-muted)}
@media (max-width:480px){.mc{padding:20px 16px}}
@media (prefers-reduced-motion:reduce){.mc *,.mc *::before{transition:none!important}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#55587a] uppercase">Filters and counts with :has() and CSS counters</span>
<section class="group/mc rounded-[20px] border border-[#e3e4f3] bg-white p-6 text-[#16173a] shadow-[0_20px_44px_-30px_rgba(22,23,58,.45)] [counter-reset:left_done] max-[480px]:px-4 max-[480px]:py-5" aria-labelledby="garden-title">
  <div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-3"><h2 class="text-[1.2rem] font-extrabold tracking-[-.015em]" id="garden-title">Garden weekend</h2>
    <fieldset class="flex min-w-0 gap-0.5 rounded-full bg-[#eceefc] p-[3px]"><legend class="sr-only">Show tasks</legend><label class="relative cursor-pointer"><input class="peer absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="garden-show" value="all" checked><span class="block rounded-full px-3.5 py-1.5 text-[.85rem] font-[650] text-[#55587a] transition-colors duration-150 hover:text-[#16173a] peer-checked:bg-white peer-checked:text-[#16173a] peer-checked:shadow-[0_1px_3px_rgba(22,23,58,.2)] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[#4338ca] motion-reduce:transition-none">All</span></label><label class="relative cursor-pointer"><input class="peer absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="garden-show" value="active"><span class="block rounded-full px-3.5 py-1.5 text-[.85rem] font-[650] text-[#55587a] transition-colors duration-150 hover:text-[#16173a] peer-checked:bg-white peer-checked:text-[#16173a] peer-checked:shadow-[0_1px_3px_rgba(22,23,58,.2)] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[#4338ca] motion-reduce:transition-none">To do</span></label><label class="relative cursor-pointer"><input class="peer absolute inset-0 m-0 size-full cursor-pointer opacity-0" type="radio" name="garden-show" value="done"><span class="block rounded-full px-3.5 py-1.5 text-[.85rem] font-[650] text-[#55587a] transition-colors duration-150 hover:text-[#16173a] peer-checked:bg-white peer-checked:text-[#16173a] peer-checked:shadow-[0_1px_3px_rgba(22,23,58,.2)] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[#4338ca] motion-reduce:transition-none">Done</span></label></fieldset></div>
  <ul class="mt-3.5 border-t border-[#e3e4f3]" aria-label="Garden tasks">
    <li class="flex items-center gap-3 border-b border-[#e3e4f3] px-1 py-[11px] [counter-increment:left] has-checked:[counter-increment:done] group-has-[[value=active]:checked]/mc:has-checked:mc-gone group-has-[[value=done]:checked]/mc:not-has-checked:mc-gone"><input class="peer size-[22px] flex-none cursor-pointer appearance-none rounded-[7px] border-2 border-[#7d80a6] bg-white bg-[length:14px] bg-center bg-no-repeat transition-colors duration-150 checked:border-[#4338ca] checked:bg-[#4338ca] checked:bg-tick focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none" type="checkbox" id="garden-1" data-task checked><label class="min-w-0 flex-1 cursor-pointer text-base leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="garden-1">Mow the back lawn</label></li>
    <li class="flex items-center gap-3 border-b border-[#e3e4f3] px-1 py-[11px] [counter-increment:left] has-checked:[counter-increment:done] group-has-[[value=active]:checked]/mc:has-checked:mc-gone group-has-[[value=done]:checked]/mc:not-has-checked:mc-gone"><input class="peer size-[22px] flex-none cursor-pointer appearance-none rounded-[7px] border-2 border-[#7d80a6] bg-white bg-[length:14px] bg-center bg-no-repeat transition-colors duration-150 checked:border-[#4338ca] checked:bg-[#4338ca] checked:bg-tick focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none" type="checkbox" id="garden-2" data-task><label class="min-w-0 flex-1 cursor-pointer text-base leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="garden-2">Plant the tulip bulbs along the fence</label></li>
    <li class="flex items-center gap-3 border-b border-[#e3e4f3] px-1 py-[11px] [counter-increment:left] has-checked:[counter-increment:done] group-has-[[value=active]:checked]/mc:has-checked:mc-gone group-has-[[value=done]:checked]/mc:not-has-checked:mc-gone"><input class="peer size-[22px] flex-none cursor-pointer appearance-none rounded-[7px] border-2 border-[#7d80a6] bg-white bg-[length:14px] bg-center bg-no-repeat transition-colors duration-150 checked:border-[#4338ca] checked:bg-[#4338ca] checked:bg-tick focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none" type="checkbox" id="garden-3" data-task><label class="min-w-0 flex-1 cursor-pointer text-base leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="garden-3">Fix the latch on the side gate</label></li>
    <li class="flex items-center gap-3 border-b border-[#e3e4f3] px-1 py-[11px] [counter-increment:left] has-checked:[counter-increment:done] group-has-[[value=active]:checked]/mc:has-checked:mc-gone group-has-[[value=done]:checked]/mc:not-has-checked:mc-gone"><input class="peer size-[22px] flex-none cursor-pointer appearance-none rounded-[7px] border-2 border-[#7d80a6] bg-white bg-[length:14px] bg-center bg-no-repeat transition-colors duration-150 checked:border-[#4338ca] checked:bg-[#4338ca] checked:bg-tick focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none" type="checkbox" id="garden-4" data-task checked><label class="min-w-0 flex-1 cursor-pointer text-base leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="garden-4">Clean out the bird bath</label></li>
    <li class="flex items-center gap-3 border-b border-[#e3e4f3] px-1 py-[11px] [counter-increment:left] has-checked:[counter-increment:done] group-has-[[value=active]:checked]/mc:has-checked:mc-gone group-has-[[value=done]:checked]/mc:not-has-checked:mc-gone"><input class="peer size-[22px] flex-none cursor-pointer appearance-none rounded-[7px] border-2 border-[#7d80a6] bg-white bg-[length:14px] bg-center bg-no-repeat transition-colors duration-150 checked:border-[#4338ca] checked:bg-[#4338ca] checked:bg-tick focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none" type="checkbox" id="garden-5" data-task><label class="min-w-0 flex-1 cursor-pointer text-base leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="garden-5">Take the green waste to the tip</label></li>
  </ul>
  <p class="hidden px-2 py-[22px] text-center text-[.95rem] text-[#55587a] group-has-[[value=done]:checked]/mc:not-group-has-[[data-task]:checked]/mc:block">Nothing ticked off yet.</p>
  <p class="hidden px-2 py-[22px] text-center text-[.95rem] text-[#55587a] group-has-[[value=active]:checked]/mc:not-group-has-[[data-task]:not(:checked)]/mc:block">Everything on this list is done.</p>
  <p class="mt-3.5 text-[.88rem] font-[650] text-[#55587a]"><span class="before:content-[counter(left)]"></span> to do<span aria-hidden="true"> · </span><span class="before:content-[counter(done)]"></span> done<span class="hidden text-[#3730a3] not-group-has-[[data-task]:not(:checked)]/mc:inline"> · All finished, enjoy the garden</span></p>
</section></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#55587a] uppercase">Hide completed, native checkboxes, growing notes</span>
<section class="group/club rounded-[20px] border border-[#e3e4f3] bg-white p-6 text-[#16173a] shadow-[0_20px_44px_-30px_rgba(22,23,58,.45)] [counter-reset:left_done] max-[480px]:px-4 max-[480px]:py-5" aria-labelledby="club-title">
  <div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-3"><div><h2 class="text-[1.2rem] font-extrabold tracking-[-.015em]" id="club-title">Book club at mine</h2><p class="mt-[3px] text-[.85rem] text-[#55587a] [&_cite]:italic">Friday 19:30 · <cite>The Lighthouse Keeper’s Daughter</cite></p></div>
    <label class="inline-flex cursor-pointer items-center gap-[9px] text-[.88rem] font-[650] text-[#55587a]"><input class="relative h-[22px] w-[38px] flex-none cursor-pointer appearance-none rounded-full bg-[#7d80a6] transition-colors duration-200 before:absolute before:top-[3px] before:left-[3px] before:size-4 before:rounded-full before:bg-white before:shadow-[0_1px_2px_rgba(0,0,0,.25)] before:transition-[translate] before:duration-200 checked:bg-[#4338ca] checked:before:translate-x-4 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca] motion-reduce:transition-none motion-reduce:before:transition-none" type="checkbox" role="switch" data-hide><span>Hide completed</span></label></div>
  <ul class="mt-3.5 grid gap-1.5" aria-label="Book club tasks">
    <li class="flex items-center gap-[11px] rounded-xl bg-[#f6f7fd] px-3 py-2.5 transition-colors duration-150 has-checked:bg-transparent has-checked:shadow-[inset_0_0_0_1px_#e3e4f3] group-has-[[data-hide]:checked]/club:has-checked:hidden motion-reduce:transition-none"><input class="peer size-[18px] flex-none cursor-pointer accent-[#4338ca] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca]" type="checkbox" id="club-1" data-task checked><label class="min-w-0 flex-1 cursor-pointer text-[.98rem] leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="club-1">Buy two bottles of white wine</label></li>
    <li class="flex items-center gap-[11px] rounded-xl bg-[#f6f7fd] px-3 py-2.5 transition-colors duration-150 has-checked:bg-transparent has-checked:shadow-[inset_0_0_0_1px_#e3e4f3] group-has-[[data-hide]:checked]/club:has-checked:hidden motion-reduce:transition-none"><input class="peer size-[18px] flex-none cursor-pointer accent-[#4338ca] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca]" type="checkbox" id="club-2" data-task><label class="min-w-0 flex-1 cursor-pointer text-[.98rem] leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="club-2">Bake the lemon drizzle cake</label></li>
    <li class="flex items-center gap-[11px] rounded-xl bg-[#f6f7fd] px-3 py-2.5 transition-colors duration-150 has-checked:bg-transparent has-checked:shadow-[inset_0_0_0_1px_#e3e4f3] group-has-[[data-hide]:checked]/club:has-checked:hidden motion-reduce:transition-none"><input class="peer size-[18px] flex-none cursor-pointer accent-[#4338ca] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca]" type="checkbox" id="club-3" data-task checked><label class="min-w-0 flex-1 cursor-pointer text-[.98rem] leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="club-3">Print the discussion questions</label></li>
    <li class="flex items-center gap-[11px] rounded-xl bg-[#f6f7fd] px-3 py-2.5 transition-colors duration-150 has-checked:bg-transparent has-checked:shadow-[inset_0_0_0_1px_#e3e4f3] group-has-[[data-hide]:checked]/club:has-checked:hidden motion-reduce:transition-none"><input class="peer size-[18px] flex-none cursor-pointer accent-[#4338ca] focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#4338ca]" type="checkbox" id="club-4" data-task><label class="min-w-0 flex-1 cursor-pointer text-[.98rem] leading-[1.4] peer-checked:text-[#55587a] peer-checked:line-through" for="club-4">Borrow four extra chairs from Ana</label></li>
  </ul>
  <p class="mt-2.5 hidden text-[.85rem] text-[#55587a] group-has-[[data-hide]:checked]/club:group-has-[[data-task]:checked]/club:block">Completed tasks are hidden.</p>
  <label class="mt-[18px] block text-[.85rem] font-bold" for="club-notes">Notes for the evening</label>
  <textarea class="mt-1.5 block max-h-[calc(10lh+20px)] min-h-[calc(3lh+20px)] w-full resize-none rounded-xl border-[1.5px] border-[#7d80a6] bg-white px-3 py-2.5 text-[.95rem] leading-normal text-[#16173a] [field-sizing:content] focus:border-[#4338ca] focus:outline-3 focus:outline-offset-1 focus:outline-[#4338ca]" id="club-notes" rows="2">Ana arrives early to help set up.
Tom is bringing the vegan option.</textarea>
  <p class="mt-1.5 text-[.8rem] text-[#55587a]">The field grows as you type, up to ten lines.</p>
</section></div>
CSS
/* the tick inside a checked box, and the collapsed state for filtered rows: visibility:hidden keeps
   them in the CSS counters, which display:none would not */
@utility bg-tick {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E");
}
@utility mc-gone {
  visibility: hidden;
  block-size: 0;
  padding-block: 0;
  border-width: 0;
  overflow: hidden;
}

About this set

Two to-do lists that do in CSS what most to-do lists need JavaScript for. Garden weekend has All, To do and Done filters built from a radio group: a :has() rule on the card reads the checked filter and hides the rows that do not match, and empty-state messages such as Everything on this list is done appear the same way. A footer reads 3 to do and 2 done from CSS counters. Filtered rows are collapsed with visibility hidden and zero height instead of display none, because CSS counters skip elements that are not displayed, so the counts stay right whichever filter is on, and an All finished note appears when every box is ticked. Book club at mine pairs native checkboxes coloured with accent-color with a Hide completed switch that hides ticked rows through :has(), and a notes field that grows with its content through field-sizing: content, between three and ten lines. Nothing in the set uses JavaScript, so nothing is saved and nothing can be added; the set shows how far filtering, counting and empty states can go with CSS alone.

What’s included

  • All, To do and Done filters from a radio group and :has(), no JavaScript
  • Counts from CSS counters that survive filtering
  • Empty states and an all-done note shown with :has()
  • Hide completed switch and native accent-color checkboxes
  • Notes field that grows with field-sizing: content

Accessibility

The filters are native radio buttons in a fieldset with a Show tasks legend, the hide switch is a checkbox with role="switch", and every task is a real checkbox with a label. Filtered rows use visibility hidden, so they leave the tab order and the accessibility tree. The counts are CSS generated content, which current browsers expose to screen readers, but there is no script, so changes are not announced. Every control shows a visible focus outline, and transitions stop under prefers-reduced-motion.

Customise it

Change --mc-accent, --mc-accent-dark, --mc-tint and --mc-box on .mc; accent-color follows --mc-accent. Bootstrap uses the same variables on .btn-check, .form-switch and .form-check-input; in Tailwind swap the #4338ca and #eceefc utilities.