143Syntax highlighter
The system's code surface — a title bar with the file name, copy / ask-AI / share / wrap actions, line numbers, diff-marked lines, and a footer whose one job is Run. Three chromes (block, mac, vscode) differ ONLY in the bar: the body, the palette, the footer and every interaction are identical, because a code block whose copy button moves depending on its skin is two components pretending to be one. Highlighting happens at build time via components/core/highlight.js, which maps any grammar onto seven roles — adding a language means adding a keyword list, never a colour.
Use it for
- Lesson and docs code samples — anything longer than a term
- A multi-file sample, as vscode tabs
- Showing a change: added, removed and called-out lines
- A runnable snippet, where the product supplies the runner
Not for
- A single term inside a sentence — that is
.ns-code-inline - An editor. This renders code; it does not edit it
- Highlighting on the client — the markup arrives tokenised, so readers do not download a grammar to re-derive what the build already knew
Anatomy
Bar, body, and the four chrome actions. The file name is always mono and always present — a code block without a name is a code block you cannot refer to. Live: copy, wrap, and both menus work on this page.
public with sharing class CaseRouter { // Route new cases to the right queue. public static void route(List<Case> cases) { for (Case c : cases) c.OwnerId = queueFor(c.Origin); }}
markup
<figure class="ns-code" data-lang="apex">
<figcaption class="ns-code__bar">
<span class="ns-code__file"><i class="ph ph-code" aria-hidden="true"></i><span>CaseRouter.cls</span></span>
<span class="ns-code__actions">
<span class="ns-code__lang">apex</span>
<button type="button" class="ns-code__btn ns-code__btn--icon" data-code="wrap" aria-pressed="false" aria-label="Wrap long lines"><i class="ph ph-text-align-justify" aria-hidden="true"></i></button>
<button type="button" class="ns-code__btn" popovertarget="ai-anatomy"><i class="ph ph-sparkle" aria-hidden="true"></i><span class="ns-code__btn-label">Ask AI</span></button>
<div id="ai-anatomy" popover="auto" class="ns-popover ns-menu ns-code__menu">
<p class="ns-menu__label">Ask about this code</p>
<a class="ns-menu__item" href="https://claude.ai/new" target="_blank" rel="noopener"><i class="ph ph-sparkle" aria-hidden="true"></i>Ask Claude</a>
<button type="button" class="ns-menu__item" data-code="ask" data-provider="explain"><i class="ph ph-lightbulb" aria-hidden="true"></i>Explain this code</button>
<button type="button" class="ns-menu__item" data-code="ask" data-provider="tests"><i class="ph ph-list-checks" aria-hidden="true"></i>Write tests for it</button>
<button type="button" class="ns-menu__item" data-code="ask" data-provider="review"><i class="ph ph-magnifying-glass" aria-hidden="true"></i>Review for bugs</button>
<p class="ns-code__menu-note">The code and its language go to the assistant you pick. Nothing leaves the page until you choose one.</p>
</div>
<button type="button" class="ns-code__btn ns-code__btn--icon" popovertarget="share-anatomy" aria-label="Share this snippet"><i class="ph ph-share-network" aria-hidden="true"></i></button>
<div id="share-anatomy" popover="auto" class="ns-popover ns-menu ns-code__menu">
<p class="ns-menu__label">Share</p>
<button type="button" class="ns-menu__item" data-code="share"><i class="ph ph-link-simple" aria-hidden="true"></i>Copy link</button>
<button type="button" class="ns-menu__item" data-code="share" data-share="native"><i class="ph ph-arrow-up-right" aria-hidden="true"></i>Share via…</button>
</div>
<button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button>
</span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4
5
6</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">public</span> <span class="ns-tok-kw">with</span> <span class="ns-tok-kw">sharing</span> <span class="ns-tok-kw">class</span> <span class="ns-tok-type">CaseRouter</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-com">// Route new cases to the right queue.</span></span><span class="ns-code__line"> <span class="ns-tok-kw">public</span> <span class="ns-tok-kw">static</span> <span class="ns-tok-kw">void</span> <span class="ns-tok-fn">route</span><span class="ns-tok-punct">(</span><span class="ns-tok-type">List</span><span class="ns-tok-punct"><</span><span class="ns-tok-type">Case</span><span class="ns-tok-punct">></span> cases<span class="ns-tok-punct">)</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-kw">for</span> <span class="ns-tok-punct">(</span><span class="ns-tok-type">Case</span> c <span class="ns-tok-punct">:</span> cases<span class="ns-tok-punct">)</span> c<span class="ns-tok-punct">.</span><span class="ns-tok-type">OwnerId</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-fn">queueFor</span><span class="ns-tok-punct">(</span>c<span class="ns-tok-punct">.</span><span class="ns-tok-type">Origin</span><span class="ns-tok-punct">);</span></span><span class="ns-code__line"> <span class="ns-tok-punct">}</span></span><span class="ns-code__line"><span class="ns-tok-punct">}</span></span></code></pre>
</div>
</figure>mac window
Traffic lights and a centred title. The dots are drawn from the STATUS tokens, not from literal red/amber/green — the shape quotes macOS, the palette stays this system's. They carry no behaviour and are aria-hidden: a window control that does not control a window must not be a button.
export function useCourseProgress(id) { const [done, setDone] = useState(0); useEffect(() => { fetchProgress(id).then(setDone); }, [id]); return done;}
markup
<figure class="ns-code ns-code--mac" data-lang="javascript">
<figcaption class="ns-code__bar">
<span class="ns-code__dots" aria-hidden="true"><i></i><i></i><i></i></span>
<span class="ns-code__file"><span>useCourseProgress.js</span></span>
<span class="ns-code__actions">
<button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button>
</span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4
5</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">export</span> <span class="ns-tok-kw">function</span> <span class="ns-tok-fn">useCourseProgress</span><span class="ns-tok-punct">(</span>id<span class="ns-tok-punct">)</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-kw">const</span> <span class="ns-tok-punct">[</span>done<span class="ns-tok-punct">,</span> setDone<span class="ns-tok-punct">]</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-fn">useState</span><span class="ns-tok-punct">(</span><span class="ns-tok-num">0</span><span class="ns-tok-punct">);</span></span><span class="ns-code__line"> <span class="ns-tok-fn">useEffect</span><span class="ns-tok-punct">(()</span> <span class="ns-tok-punct">=></span> <span class="ns-tok-punct">{</span> <span class="ns-tok-fn">fetchProgress</span><span class="ns-tok-punct">(</span>id<span class="ns-tok-punct">).</span><span class="ns-tok-fn">then</span><span class="ns-tok-punct">(</span>setDone<span class="ns-tok-punct">);</span> <span class="ns-tok-punct">},</span> <span class="ns-tok-punct">[</span>id<span class="ns-tok-punct">]);</span></span><span class="ns-code__line"> <span class="ns-tok-kw">return</span> done<span class="ns-tok-punct">;</span></span><span class="ns-code__line"><span class="ns-tok-punct">}</span></span></code></pre>
</div>
</figure>vscode window
A tab strip above and a brand status bar below. The active tab is the one whose background matches the code underneath it — a tab is a piece cut out of the editor surface, which is the whole visual idea. The 2px top accent is the same current-item device the navbar uses. Live: click the tabs, or use arrow keys.
public with sharing class CaseRouter { public static void route(List<Case> cases) { for (Case c : cases) c.OwnerId = queueFor(c.Origin); }}
@isTestprivate class CaseRouterTest { @isTest static void routesWebCases() { System.assertEquals(1, 1, 'placeholder'); }}
SELECT Id, Name FROM GroupWHERE Type = 'Queue'ORDER BY Name ASC
markup
<figure class="ns-code ns-code--vscode" data-lang="apex">
<div class="ns-code__tabs" role="tablist" aria-label="Sample files">
<button type="button" role="tab" class="ns-code__tab" aria-selected="true" tabindex="0" aria-controls="vs-p1" id="vs-t1"><i class="ph ph-code" aria-hidden="true"></i>CaseRouter.cls</button>
<button type="button" role="tab" class="ns-code__tab" aria-selected="false" tabindex="-1" aria-controls="vs-p2" id="vs-t2"><i class="ph ph-code" aria-hidden="true"></i>CaseRouterTest.cls</button>
<button type="button" role="tab" class="ns-code__tab" aria-selected="false" tabindex="-1" aria-controls="vs-p3" id="vs-t3"><i class="ph ph-code" aria-hidden="true"></i>queues.soql</button>
</div>
<div role="tabpanel" id="vs-p1" aria-labelledby="vs-t1">
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4
5</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">public</span> <span class="ns-tok-kw">with</span> <span class="ns-tok-kw">sharing</span> <span class="ns-tok-kw">class</span> <span class="ns-tok-type">CaseRouter</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-kw">public</span> <span class="ns-tok-kw">static</span> <span class="ns-tok-kw">void</span> <span class="ns-tok-fn">route</span><span class="ns-tok-punct">(</span><span class="ns-tok-type">List</span><span class="ns-tok-punct"><</span><span class="ns-tok-type">Case</span><span class="ns-tok-punct">></span> cases<span class="ns-tok-punct">)</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-kw">for</span> <span class="ns-tok-punct">(</span><span class="ns-tok-type">Case</span> c <span class="ns-tok-punct">:</span> cases<span class="ns-tok-punct">)</span> c<span class="ns-tok-punct">.</span><span class="ns-tok-type">OwnerId</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-fn">queueFor</span><span class="ns-tok-punct">(</span>c<span class="ns-tok-punct">.</span><span class="ns-tok-type">Origin</span><span class="ns-tok-punct">);</span></span><span class="ns-code__line"> <span class="ns-tok-punct">}</span></span><span class="ns-code__line"><span class="ns-tok-punct">}</span></span></code></pre>
</div>
</div>
<div role="tabpanel" id="vs-p2" aria-labelledby="vs-t2" hidden>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4
5
6</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line">@isTest</span><span class="ns-code__line"><span class="ns-tok-kw">private</span> <span class="ns-tok-kw">class</span> <span class="ns-tok-type">CaseRouterTest</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> @isTest <span class="ns-tok-kw">static</span> <span class="ns-tok-kw">void</span> <span class="ns-tok-fn">routesWebCases</span><span class="ns-tok-punct">()</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line"> <span class="ns-tok-type">System</span><span class="ns-tok-punct">.</span><span class="ns-tok-fn">assertEquals</span><span class="ns-tok-punct">(</span><span class="ns-tok-num">1</span><span class="ns-tok-punct">,</span> <span class="ns-tok-num">1</span><span class="ns-tok-punct">,</span> <span class="ns-tok-str">'placeholder'</span><span class="ns-tok-punct">);</span></span><span class="ns-code__line"> <span class="ns-tok-punct">}</span></span><span class="ns-code__line"><span class="ns-tok-punct">}</span></span></code></pre>
</div>
</div>
<div role="tabpanel" id="vs-p3" aria-labelledby="vs-t3" hidden>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">SELECT</span> <span class="ns-tok-type">Id</span><span class="ns-tok-punct">,</span> <span class="ns-tok-type">Name</span> <span class="ns-tok-kw">FROM</span> <span class="ns-tok-type">Group</span></span><span class="ns-code__line"><span class="ns-tok-kw">WHERE</span> <span class="ns-tok-type">Type</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-str">'Queue'</span></span><span class="ns-code__line"><span class="ns-tok-kw">ORDER</span> <span class="ns-tok-kw">BY</span> <span class="ns-tok-type">Name</span> <span class="ns-tok-kw">ASC</span></span></code></pre>
</div>
</div>
<div class="ns-code__foot">
<span class="ns-code__status"><i class="ph ph-check-circle" aria-hidden="true"></i>Saved</span>
<span class="ns-code__meta">apex · UTF-8 · LF</span>
</div>
</figure>Run
Run lives in the footer and nowhere else — it is the one action here that changes something, and putting it beside Copy would set a state-changing button one pixel from a harmless one. It does NOT execute anything: it raises ns:code-run and waits for the host to call done(). A design system that evaluated the code in its own docs would be a security hole with a play button on it. This demo carries data-output, which is the documented stand-in.
SELECT Id, Name, DeveloperNameFROM GroupWHERE Type = 'Queue'ORDER BY Name ASC LIMIT 200
markup
<figure class="ns-code" data-lang="soql" data-output="Rows: 3
Support Queue · 00G5g000004bYtR
Escalations Queue · 00G5g000004bYtS
Partner Queue · 00G5g000004bYtT
Completed in 0.42s">
<figcaption class="ns-code__bar">
<span class="ns-code__file"><i class="ph ph-database" aria-hidden="true"></i><span>queues.soql</span></span>
<span class="ns-code__actions">
<span class="ns-code__lang">soql</span>
<button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button>
</span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">SELECT</span> <span class="ns-tok-type">Id</span><span class="ns-tok-punct">,</span> <span class="ns-tok-type">Name</span><span class="ns-tok-punct">,</span> <span class="ns-tok-type">DeveloperName</span></span><span class="ns-code__line"><span class="ns-tok-kw">FROM</span> <span class="ns-tok-type">Group</span></span><span class="ns-code__line"><span class="ns-tok-kw">WHERE</span> <span class="ns-tok-type">Type</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-str">'Queue'</span></span><span class="ns-code__line"><span class="ns-tok-kw">ORDER</span> <span class="ns-tok-kw">BY</span> <span class="ns-tok-type">Name</span> <span class="ns-tok-kw">ASC</span> <span class="ns-tok-kw">LIMIT</span> <span class="ns-tok-num">200</span></span></code></pre>
</div>
<div class="ns-code__foot">
<button type="button" class="ns-code__run" data-code="run"><i class="ph ph-play" aria-hidden="true"></i>Run</button>
<span class="ns-code__status" data-code-status></span>
<span class="ns-code__meta">4 lines · 118 B</span>
</div>
<output class="ns-code__out" aria-live="polite" hidden></output>
</figure>Marked lines
Added, removed and called-out lines — a 2px leading edge plus a wash, the same accent-line device the rest of the system uses. Diff colour is never the only signal: the sample is introduced in prose, because a red line and a green line are one colour to a monochromat.
public static void route(List<Case> cases) { Map<String, Id> queues = queueMap(); for (Case c : cases) { c.OwnerId = [SELECT Id FROM Group WHERE DeveloperName = :c.Origin].Id; c.OwnerId = queues.get(c.Origin); }}
markup
<figure class="ns-code" data-lang="apex">
<figcaption class="ns-code__bar">
<span class="ns-code__file"><i class="ph ph-git-branch" aria-hidden="true"></i><span>CaseRouter.cls — the bulkification fix</span></span>
<span class="ns-code__actions"><button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button></span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2
3
4
5
6
7</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">public</span> <span class="ns-tok-kw">static</span> <span class="ns-tok-kw">void</span> <span class="ns-tok-fn">route</span><span class="ns-tok-punct">(</span><span class="ns-tok-type">List</span><span class="ns-tok-punct"><</span><span class="ns-tok-type">Case</span><span class="ns-tok-punct">></span> cases<span class="ns-tok-punct">)</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line ns-code__line--mark"> <span class="ns-tok-type">Map</span><span class="ns-tok-punct"><</span><span class="ns-tok-type">String</span><span class="ns-tok-punct">,</span> <span class="ns-tok-type">Id</span><span class="ns-tok-punct">></span> queues <span class="ns-tok-punct">=</span> <span class="ns-tok-fn">queueMap</span><span class="ns-tok-punct">();</span></span><span class="ns-code__line"> <span class="ns-tok-kw">for</span> <span class="ns-tok-punct">(</span><span class="ns-tok-type">Case</span> c <span class="ns-tok-punct">:</span> cases<span class="ns-tok-punct">)</span> <span class="ns-tok-punct">{</span></span><span class="ns-code__line ns-code__line--del"> c<span class="ns-tok-punct">.</span><span class="ns-tok-type">OwnerId</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-punct">[</span><span class="ns-tok-kw">SELECT</span> <span class="ns-tok-type">Id</span> <span class="ns-tok-kw">FROM</span> <span class="ns-tok-type">Group</span> <span class="ns-tok-kw">WHERE</span> <span class="ns-tok-type">DeveloperName</span> <span class="ns-tok-punct">=</span> <span class="ns-tok-punct">:</span>c<span class="ns-tok-punct">.</span><span class="ns-tok-type">Origin</span><span class="ns-tok-punct">].</span><span class="ns-tok-type">Id</span><span class="ns-tok-punct">;</span></span><span class="ns-code__line ns-code__line--add"> c<span class="ns-tok-punct">.</span><span class="ns-tok-type">OwnerId</span> <span class="ns-tok-punct">=</span> queues<span class="ns-tok-punct">.</span><span class="ns-tok-kw">get</span><span class="ns-tok-punct">(</span>c<span class="ns-tok-punct">.</span><span class="ns-tok-type">Origin</span><span class="ns-tok-punct">);</span></span><span class="ns-code__line"> <span class="ns-tok-punct">}</span></span><span class="ns-code__line"><span class="ns-tok-punct">}</span></span></code></pre>
</div>
</figure>On the console surface
--dark forces the navy console on a light page, which is what a docs body wants: code should look like code, not like an indented paragraph. Under [data-theme="dark"] every block goes here automatically, so this modifier is only for the light-page case.
# Deploy the metadata, then run the local tests only.sf project deploy start --source-dir force-app --test-level RunLocalTests --wait 30
markup
<figure class="ns-code ns-code--dark" data-lang="bash">
<figcaption class="ns-code__bar">
<span class="ns-code__file"><i class="ph ph-terminal-window" aria-hidden="true"></i><span>deploy.sh</span></span>
<span class="ns-code__actions"><button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button></span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__gutter" aria-hidden="true">1
2</pre>
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-com"># Deploy the metadata, then run the local tests only.</span></span><span class="ns-code__line">sf project deploy start <span class="ns-tok-punct">--</span><span class="ns-tok-kw">source</span><span class="ns-tok-punct">-</span>dir force<span class="ns-tok-punct">-</span>app <span class="ns-tok-punct">--</span>test<span class="ns-tok-punct">-</span>level <span class="ns-tok-type">RunLocalTests</span> <span class="ns-tok-punct">--</span>wait <span class="ns-tok-num">30</span></span></code></pre>
</div>
</figure>Compact, no gutter, inline
--compact tightens leading and drops a size, for a sample set beside prose rather than under a heading. Dropping the gutter is right whenever the lines are not going to be referred to by number. The inline chip is the one-liner sibling: same mono, same sunken chip, no chrome.
import { tokens } from "@namaste-salesforce/design-system";
Set the reading weight with --weight-body, never with font-weight: 400.
markup
<figure class="ns-code ns-code--compact" data-lang="javascript">
<figcaption class="ns-code__bar">
<span class="ns-code__file"><span>tokens.js</span></span>
<span class="ns-code__actions"><button type="button" class="ns-code__btn" data-code="copy"><i class="ph ph-file-text" aria-hidden="true"></i><span class="ns-code__btn-label"><span>Copy</span></span></button></span>
</figcaption>
<div class="ns-code__body">
<pre class="ns-code__pre"><code><span class="ns-code__line"><span class="ns-tok-kw">import</span> <span class="ns-tok-punct">{</span> tokens <span class="ns-tok-punct">}</span> <span class="ns-tok-kw">from</span> <span class="ns-tok-str">"@namaste-salesforce/design-system"</span><span class="ns-tok-punct">;</span></span></code></pre>
</div>
</figure>
<p>Set the reading weight with <code class="ns-code-inline">--weight-body</code>, never with <code class="ns-code-inline">font-weight: 400</code>.</p>Accessibility contract
- Line numbers live in a separate aria-hidden gutter, so they are never announced and never land in the clipboard
- The Ask-AI and Share menus are native popovers: light-dismiss, Esc and focus return come from the platform, not from a re-implementation
- The tab strip is a real tablist — arrow keys, Home/End, and one tab stop for the whole strip
- Run's result renders into an aria-live="polite" output, so the outcome of the button you pressed is announced
- Every icon-only control (wrap, share) carries an aria-label; the copy confirmation is a text change, not a colour change
- The seven syntax roles all clear 4.5:1 on their own surface in both themes — syntax colour is decoration on top of code that reads without it