NS Design System
v3.0.0 · 257 tokens

87Course listing

The catalog: a filter row (tags with aria-pressed + a sort Select) over the course-card grid. This demo is LIVE — the tags actually filter the grid; hidden cards keep their colors and order when they return.

Use it for

  • The /courses page, tag archives, search results

Not for

  • A shelf of 4 on the home page — Carousel or a plain grid

Live filter + grid

Beginner
// CourseApex basics12 lessons
Beginner
// CourseAdmin fundamentals14 lessons
Intermediate
// CourseFlows, end to end9 lessons
Advanced
// CourseBulk-safe Apex9 lessons
markup
<div id="cl-demo" style="inline-size:100%">
  <div class="ns-course-filters">
    <button class="ns-tag" data-filter="all" aria-pressed="true">All</button>
    <button class="ns-tag" data-filter="admin" aria-pressed="false">Admin</button>
    <button class="ns-tag" data-filter="dev" aria-pressed="false">Developer</button>
    <span class="ns-ccard__meta" data-count role="status" style="margin-inline-start:var(--space-2)"></span>
    <select class="ns-select" aria-label="Sort">
      <option>Newest</option><option>Most popular</option><option>Shortest first</option>
    </select>
  </div>
  <div class="ns-course-grid">
    <div class="ns-card ns-ccard" data-topic="dev"><span class="ns-ccard__mediawrap"><span class="ns-card__media ns-ph" aria-hidden="true"></span><span class="ns-tag ns-ccard__level">Beginner</span></span><div class="ns-card__body"><span class="ns-card__kicker">// Course</span><a class="ns-card__link" href="#"><span class="ns-card__title">Apex basics</span></a><span class="ns-ccard__meta"><span>12 lessons</span></span></div></div>
    <div class="ns-card ns-ccard" data-topic="admin"><span class="ns-ccard__mediawrap"><span class="ns-card__media ns-ph" aria-hidden="true"></span><span class="ns-tag ns-ccard__level">Beginner</span></span><div class="ns-card__body"><span class="ns-card__kicker">// Course</span><a class="ns-card__link" href="#"><span class="ns-card__title">Admin fundamentals</span></a><span class="ns-ccard__meta"><span>14 lessons</span></span></div></div>
    <div class="ns-card ns-ccard" data-topic="admin"><span class="ns-ccard__mediawrap"><span class="ns-card__media ns-ph" aria-hidden="true"></span><span class="ns-tag ns-ccard__level">Intermediate</span></span><div class="ns-card__body"><span class="ns-card__kicker">// Course</span><a class="ns-card__link" href="#"><span class="ns-card__title">Flows, end to end</span></a><span class="ns-ccard__meta"><span>9 lessons</span></span></div></div>
    <div class="ns-card ns-ccard" data-topic="dev"><span class="ns-ccard__mediawrap"><span class="ns-card__media ns-ph" aria-hidden="true"></span><span class="ns-tag ns-ccard__level">Advanced</span></span><div class="ns-card__body"><span class="ns-card__kicker">// Course</span><a class="ns-card__link" href="#"><span class="ns-card__title">Bulk-safe Apex</span></a><span class="ns-ccard__meta"><span>9 lessons</span></span></div></div>
  </div>
</div>

Full page

markup
<p><a class="ns-btn ns-btn--outline ns-btn--sm" href="./demo-course-listing.html" target="_blank" rel="noopener">Open the full-screen demo <i class="ph ph-arrow-up-right" aria-hidden="true"></i></a></p>

Accessibility contract

  • Filters are real buttons; the result count is a live region so the change is announced
  • An emptied grid shows the Empty state with the one obvious fix — clear filters