NS Design System
v3.0.0 · 257 tokens

82Course card

The Card with course anatomy: level tag riding the media, mono meta row, and a progress foot with the real element. A row of these is the catalog; one with progress is "continue learning".

Use it for

  • Catalog grids, related-course shelves, continue-learning rows

Not for

  • The course detail hero — that page IS the course, no card around it

Default

Beginner
// Course Apex basics

The platform's own language, from zero to first deploy.

12 lessons3h 40m
markup
<div class="ns-card ns-ccard" style="max-inline-size:18rem">
  <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>
    <p class="ns-card__text">The platform's own language, from zero to first deploy.</p>
    <span class="ns-ccard__meta"><span>12 lessons</span><span>3h 40m</span></span>
  </div>
</div>

With progress

Continue learning: the foot swaps meta for the real progress element.

Intermediate
// Course Flows, end to end Next: 07 · Approval flows
6/12
markup
<div class="ns-card ns-ccard" style="max-inline-size:18rem">
  <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>Next: 07 · Approval flows</span></span>
  </div>
  <div class="ns-ccard__progress">
    <progress class="ns-progress" value="6" max="12" aria-label="6 of 12 lessons complete"></progress>
    <span class="ns-ccard__pct">6/12</span>
  </div>
</div>

Row — continue learning

The horizontal form for the dashboard's resume shelf.

// Continue Admin certification path Lesson 08 of 1421:15 left
markup
<div class="ns-card ns-card--row ns-ccard" style="max-inline-size:30rem">
  <span class="ns-card__media ns-ph" aria-hidden="true"></span>
  <div class="ns-card__body">
    <span class="ns-card__kicker">// Continue</span>
    <a class="ns-card__link" href="#"><span class="ns-card__title">Admin certification path</span></a>
    <span class="ns-ccard__meta"><span>Lesson 08 of 14</span><span>21:15 left</span></span>
    <progress class="ns-progress" value="8" max="14" aria-label="8 of 14 lessons complete"></progress>
  </div>
</div>

Members-only

Locked stays a real link — to the join page; the lock is a tag, never an overlay wash.

Members
// Course Bulk-safe Apex patterns 9 lessons2h 10m
markup
<div class="ns-card ns-ccard" style="max-inline-size:18rem">
  <span class="ns-ccard__mediawrap">
    <span class="ns-card__media ns-ph" aria-hidden="true"></span>
    <span class="ns-tag ns-ccard__level"><i class="ph ph-lock-simple" aria-hidden="true"></i> Members</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 patterns</span></a>
    <span class="ns-ccard__meta"><span>9 lessons</span><span>2h 10m</span></span>
  </div>
</div>

Full meta

Everything a card can carry, so the parts are visible in one place: a corner flag, the runtime chip on the media, the play affordance, rating, learner count, level, authors and price. A real card picks three or four of these — this is the vocabulary, not a recommendation. The rating's NUMBER comes first in the DOM; the stars are decoration over it.

Beginner Bestseller 3h 40m
// Course Apex basics, end to end

The platform's own language, from zero to first deploy.

4.8 (1,240) 12 lessons 8,410 English Swarnil Singhai and 3 others $49 $129 62% off
markup
<div class="ns-card ns-ccard" style="max-inline-size:19rem">
  <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 class="ns-ccard__badge">Bestseller</span>
    <span class="ns-ccard__dur">3h 40m</span>
    <span class="ns-ccard__play" aria-hidden="true"><i class="ph ph-play-circle"></i></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, end to end</span></a>
    <p class="ns-card__text">The platform's own language, from zero to first deploy.</p>
    <span class="ns-rating" data-value="4.8" data-of="5">
      <span class="ns-rating__value">4.8</span>
      <span class="ns-rating__stars" aria-hidden="true">
        <span><i class="ph ph-star"></i><i class="ph ph-star"></i><i class="ph ph-star"></i><i class="ph ph-star"></i><i class="ph ph-star"></i></span>
        <span class="ns-rating__fill"><i class="ph-fill ph-star"></i><i class="ph-fill ph-star"></i><i class="ph-fill ph-star"></i><i class="ph-fill ph-star"></i><i class="ph-fill ph-star"></i></span>
      </span>
      <span class="ns-rating__count">(1,240)</span>
    </span>
    <span class="ns-ccard__meta">
      <span><i class="ph ph-list" aria-hidden="true"></i>12 lessons</span>
      <span><i class="ph ph-users-three" aria-hidden="true"></i>8,410</span>
      <span><i class="ph ph-globe" aria-hidden="true"></i>English</span>
    </span>
    <span class="ns-authors ns-authors--sm">
      <span class="ns-authors__stack" aria-hidden="true">
        <img class="ns-authors__avatar" src="../assets/logo/favicon.svg" alt="">
        <img class="ns-authors__avatar" src="../assets/logo/favicon.svg" alt="">
        <span class="ns-authors__more">+2</span>
      </span>
      <span class="ns-authors__names"><b>Swarnil Singhai</b> and 3 others</span>
    </span>
    <span class="ns-price ns-price--sm">
      <span class="ns-price__now">$49</span>
      <span class="ns-price__was">$129</span>
      <span class="ns-price__off">62% off</span>
    </span>
  </div>
</div>

Lesson peek

What is actually IN the course, without leaving the grid. Hover or tab into the card. It is real content in the DOM at all times — collapsed with a grid-template-rows transition rather than display:none, so in-page find reaches it and a screen reader reads it whether or not a pointer is over the card. Where hover does not exist it is simply open, because the alternative is content no touch user can reach. Show three or four rows: a peek listing twenty is the syllabus in the wrong place.

markup
<div class="ns-card ns-ccard" style="max-inline-size:19rem">
  <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 class="ns-ccard__dur">2h 10m</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 patterns</span></a>
    <span class="ns-ccard__meta"><span>9 lessons</span><span>Updated Aug 2026</span></span>
  </div>
  <div class="ns-ccard__peek">
    <div>
      <a class="ns-lesson" href="#"><span class="ns-lesson__index" aria-hidden="true">01</span><span class="ns-lesson__title">Why one record at a time fails</span><span class="ns-lesson__time">08:12</span></a>
      <a class="ns-lesson" href="#"><span class="ns-lesson__index" aria-hidden="true">02</span><span class="ns-lesson__title">Collections, maps and sets</span><span class="ns-lesson__time">14:40</span></a>
      <a class="ns-lesson" href="#" data-state="locked"><span class="ns-lesson__index" aria-hidden="true">03</span><span class="ns-lesson__title">Governor limits in practice</span><span class="ns-lesson__time"><i class="ph ph-lock" aria-hidden="true"></i></span></a>
      <a class="ns-ccard__peek-more" href="#">See all 9 lessons →</a>
    </div>
  </div>
</div>

Shapes

Five shapes, one anatomy — a course in a grid, in a search result, in a rail and in a related strip is the same object at four sizes, and four bespoke cards is how the meta rows drift apart. --row for lists, --compact for dense rails, --minimal for a card inside another card.

// Continue Admin certification path Lesson 08 of 1421:15 left
// Related SOQL, properly 6 lessons1h 05m
Integration patterns 11 lessonsAdvanced
markup
<div style="display:grid;gap:var(--space-4);max-inline-size:32rem">
  <div class="ns-card ns-ccard ns-ccard--row">
    <span class="ns-ccard__mediawrap"><span class="ns-card__media ns-ph" aria-hidden="true"></span></span>
    <div class="ns-card__body">
      <span class="ns-card__kicker">// Continue</span>
      <a class="ns-card__link" href="#"><span class="ns-card__title">Admin certification path</span></a>
      <span class="ns-ccard__meta"><span>Lesson 08 of 14</span><span>21:15 left</span></span>
      <progress class="ns-progress" value="8" max="14" aria-label="8 of 14 lessons complete"></progress>
    </div>
  </div>
  <div class="ns-card ns-ccard ns-ccard--compact" style="max-inline-size:14rem">
    <div class="ns-card__body">
      <span class="ns-card__kicker">// Related</span>
      <a class="ns-card__link" href="#"><span class="ns-card__title">SOQL, properly</span></a>
      <span class="ns-ccard__meta"><span>6 lessons</span><span>1h 05m</span></span>
    </div>
  </div>
  <div class="ns-card ns-ccard ns-ccard--minimal">
    <div class="ns-card__body">
      <a class="ns-card__link" href="#"><span class="ns-card__title">Integration patterns</span></a>
      <span class="ns-ccard__meta"><span>11 lessons</span><span>Advanced</span></span>
    </div>
  </div>
</div>

Featured

The one promoted course. Two columns, more meta, a larger title — and exactly one of these per screen, or it is not featured.

markup
<div class="ns-card ns-ccard ns-ccard--featured" style="max-inline-size:38rem">
  <span class="ns-ccard__mediawrap">
    <span class="ns-card__media ns-ph" aria-hidden="true"></span>
    <span class="ns-ccard__badge ns-ccard__badge--new">New</span>
  </span>
  <div class="ns-card__body">
    <span class="ns-card__kicker">// Featured path</span>
    <a class="ns-card__link" href="#"><span class="ns-card__title">The Salesforce developer track</span></a>
    <p class="ns-card__text">Six courses, one order: the data model, Apex, LWC, integration, testing and deployment.</p>
    <span class="ns-ccard__meta">
      <span><i class="ph ph-books" aria-hidden="true"></i>6 courses</span>
      <span><i class="ph ph-clock" aria-hidden="true"></i>24h</span>
      <span><i class="ph ph-medal" aria-hidden="true"></i>Certificate</span>
    </span>
    <div style="display:flex;gap:var(--space-2);margin-block-start:var(--space-2)">
      <a class="ns-btn ns-btn--primary ns-btn--sm" href="#">Start the track</a>
      <a class="ns-btn ns-btn--outline ns-btn--sm" href="#">What's inside</a>
    </div>
  </div>
</div>

Accessibility contract

  • The title link is stretched over the card — one real link
  • progress carries an aria-label with the human numbers