86Course detail page
The course's landing: hero (title, meta, the one primary action), the stat band, the outcomes, and then the five arguments — overview, curriculum, instructors, reviews, FAQ — as TABS in the content column, with the enrol card sticky in the rail beside them. One primary button on the whole page.
Use it for
- Every course's public page, both products
Not for
- The lesson experience — Course player
Anatomy — content + sticky rail
The grid at documentation scale; open the full-screen demo for the real thing.
Apex basics
Objects, triggers and your first deploy — the platform's own language from zero. Concept, concrete example, bridge to the next step: every lesson, same shape.
Getting oriented
markup
<div class="ns-course-detail" style="inline-size:100%">
<div>
<span class="ns-kicker">// Course · Beginner</span>
<h2 style="font-size:var(--size-h3);margin-block:var(--space-2) var(--space-3)">Apex basics</h2>
<p style="color:var(--color-muted);font-size:var(--size-small);max-inline-size:34rem">Objects, triggers and your first deploy — the platform's own language from zero. Concept, concrete example, bridge to the next step: every lesson, same shape.</p>
<div class="ns-curriculum" style="margin-block-start:var(--space-5)">
<section class="ns-curriculum__section">
<header class="ns-curriculum__head"><span class="ns-curriculum__index">01</span><h3 class="ns-curriculum__title">Getting oriented</h3><span class="ns-curriculum__meta">3 lessons</span></header>
<a class="ns-lesson" href="#"><span class="ns-lesson__index" aria-hidden="true">01</span><span class="ns-lesson__title">What is an org?</span><span class="ns-lesson__time"><span class="ns-tag">Free</span></span></a>
<a class="ns-lesson" href="#" data-state="locked"><span class="ns-lesson__index" aria-hidden="true">02</span><span class="ns-lesson__title">Objects & fields</span><span class="ns-lesson__time"><i class="ph ph-lock" aria-hidden="true"></i></span></a>
</section>
</div>
</div>
<aside class="ns-course-detail__rail">
<div class="ns-railbox">
<p class="ns-railbox__title">This course</p>
<p style="font-size:var(--size-small);color:var(--color-muted)">12 lessons · 3h 40m · certificate</p>
<button class="ns-btn ns-btn--primary ns-btn--block" style="margin-block-start:var(--space-3)">Start learning free</button>
</div>
<div class="ns-railbox">
<p class="ns-railbox__title">Instructor</p>
<div style="display:flex;align-items:center;gap:var(--space-3)">
<span class="ns-avatar">SW</span>
<span style="font-size:var(--size-small)">Swarnil Singhai<br><span style="color:var(--color-muted)">Salesforce architect</span></span>
</div>
</div>
</aside>
</div>Full page
Three decisions worth knowing before you copy it. Tabs, not eight stacked bands — a course page carries five separate arguments, and stacked they make a page nobody reaches the bottom of, with the curriculum (the thing people came to read) buried three screens down. Outcomes above the tabs, never inside one — "what will I be able to do" is the question every visitor arrives with, and it decides whether they read anything else; each promise takes the icon of the thing it produces rather than a fifth identical tick, because five ticks is a list that has to be read and five glyphs is one that can be scanned. The lesson kind is an icon — twenty-four rows that each spell out VIDEO turn a curriculum into a spreadsheet; the word stays in the DOM and returns as a tooltip, which frees the row's second line for what the glyph cannot say: whether the row is open to you.
markup
<p><a class="ns-btn ns-btn--outline ns-btn--sm" href="./demo-course-detail.html" target="_blank" rel="noopener">Open the full-screen demo <i class="ph ph-arrow-up-right" aria-hidden="true"></i></a></p>The five shapes
Same content, same components, five arrangements — because a $9 course, a certification track and a free tutorial are not the same sale. --wide puts the rail LEFT for a course whose curriculum is the product; --stacked drops the rail entirely (free courses: a sticky price rail advertising nothing); --syllabus leads with the curriculum for a returning learner; --compact is one prose column, the documentation-page look.
--wide
The curriculum is the product, so it gets the wide column and the price follows it down.
--stacked
No rail at all — the buy box sits after the outcomes, in the reading column.
--compact
One column at the prose measure, no media: a course documented rather than sold.
markup
<div style="display:grid;gap:var(--space-6);inline-size:100%">
<div class="ns-course-detail ns-course-detail--wide" style="border:1px solid var(--color-border);border-radius:var(--radius-card);padding:var(--pad-card)">
<aside class="ns-course-detail__rail"><div class="ns-card"><div class="ns-card__body"><span class="ns-card__kicker">// Rail left</span><span class="ns-card__title">$49</span></div></div></aside>
<div class="ns-course-detail__main"><p class="ns-kicker">--wide</p><p>The curriculum is the product, so it gets the wide column and the price follows it down.</p></div>
</div>
<div class="ns-course-detail ns-course-detail--stacked" style="border:1px solid var(--color-border);border-radius:var(--radius-card);padding:var(--pad-card)">
<div class="ns-course-detail__main"><p class="ns-kicker">--stacked</p><p>No rail at all — the buy box sits after the outcomes, in the reading column.</p></div>
<aside class="ns-course-detail__rail"><div class="ns-card"><div class="ns-card__body"><span class="ns-card__title">Free</span></div></div></aside>
</div>
<div class="ns-course-detail ns-course-detail--compact" style="border:1px solid var(--color-border);border-radius:var(--radius-card);padding:var(--pad-card)">
<div class="ns-course-detail__main"><p class="ns-kicker">--compact</p><p>One column at the prose measure, no media: a course documented rather than sold.</p></div>
</div>
</div>Accessibility contract
- The hero's enroll button and the rail's are the same action — one label, both reachable
- The curriculum is the real component, so its row semantics come along
- Tabs are the real ARIA pattern via assets/js/tabs.js — and with no JS every panel is visible, so the stacked page is the fallback rather than a page with four sections missing