Direct Code Block
Standalone code blocks with copy button, used for API documentation and code snippets
<div class="nds-code nds-expandable">
<div class="nds-code-action">
<button class="nds-btn nds-subtle nds-copy" aria-label="Copy code example">
<i class="nds-icon nds-hgi-copy-01"></i>
</button>
</div>
<div class="nds-expandable-content">
<code class="lang-html code">
<!-- Your code here -->
</code>
</div>
</div>
<div class="nds-code nds-expandable">
<div class="nds-code-action">
<button class="nds-btn nds-subtle nds-copy" aria-label="Copy code example">
<i class="nds-icon nds-hgi-copy-01"></i>
</button>
</div>
<div class="nds-expandable-content">
<code class="lang-javascript">
// Your code here
</code>
</div>
</div>
<div class="nds-code nds-expandable">
<div class="nds-code-action">
<button class="nds-btn nds-subtle nds-copy" aria-label="Copy code example">
<i class="nds-icon nds-hgi-copy-01"></i>
</button>
</div>
<div class="nds-expandable-content">
<code class="lang-javascript">
// Long code content here
// Will collapse with "Show More" button
</code>
</div>
</div>
Tabbed Code Block
Code blocks with tab navigation for showing multiple languages or file types
<button class="nds-btn nds-primary nds-lg">
<i class="nds-icon nds-hgi-plus-sign" aria-hidden="true"></i>
<span class="nds-label">Button Text</span>
</button>
<div class="demo-code">
<div class="nds-tabs nds-code nds-divided">
<div class="nds-tab-list-container nds-scroll-more">
<nav class="nds-tab-list nds-scroll-more-content" role="tablist" aria-label="Tab navigation">
<button class="nds-btn nds-subtle nds-tab" role="tab" aria-selected="true"
aria-controls="panel-id" id="tab-id" type="button">
<span class="nds-tab-label">HTML</span>
</button>
</nav>
<button class="nds-btn nds-subtle nds-tab nds-show-more" aria-label="Show more" type="button"><i class="nds-icon nds-hgi-arrow-down-01" aria-hidden="true"></i>
</button>
</div>
<div class="nds-tab-content">
<div class="nds-tab-panel code-example" role="tabpanel" id="panel-id"
aria-labelledby="tab-id">
<div class="nds-code-action">
<button class="nds-btn nds-subtle nds-copy" aria-label="Copy code example">
<i class="nds-icon nds-hgi-copy-01"></i>
</button>
</div>
<code class="lang-html code">
<!-- Your code here -->
</code>
</div>
</div>
</div>
</div>
<div class="nds-alert nds-card" data-status="success">
<span class="nds-feedback nds-alert-icon nds-outline">
<span class="nds-feedback-icon">
<i class="nds-icon" aria-hidden="true"></i>
</span>
</span>
<div class="nds-alert-content">
<div class="nds-alert-text">
<span class="nds-alert-title">Success</span>
<p class="nds-alert-description">Operation completed.</p>
</div>
</div>
</div>
NDS.Alert.create({
variant: 'success',
title: 'Success',
description: 'Operation completed.',
target: '#container'
});
.nds-alert {
display: flex;
align-items: flex-start;
gap: var(--spacing-md);
padding: var(--spacing-lg);
}
When used inside demo cards, tabbed code blocks start with the hidden attribute. The showcase JavaScript reveals them with a toggle button. Click the code icon below any demo card to see this in action.
Inline Code
Use nds-inline-code on a <code> element for short inline code references with syntax coloring
Call NDS.Code.init after inserting dynamic code blocks, or use the class nds-inline-code directly on any <code> element.
<p>Call <code class="nds-inline-code lang-html">NDS.Code.init</code> after inserting dynamic code blocks, or use the class <code class="nds-inline-code lang-html">nds-inline-code</code> directly on any <code class="nds-inline-code lang-html"><code></code> element.</p>
Language Classes
Supported language identifiers for the code element. When no class is present, the lexer sniffs the language from the content automatically.
| Class | Language | Usage |
|---|---|---|
lang-html |
HTML / XML | Markup and template examples |
lang-css |
CSS | Stylesheet examples. SCSS-only syntax ($vars, @mixin, // comments) is not lexed |
lang-javascript or lang-js |
JavaScript | Script and API examples |
lang-markdown or lang-md |
Markdown | Docs and agent-instruction blocks. Headings, list and quote markers, links, bold, and inline code are coloured. A fenced block is lexed as its info-string language (```html, ```css, ```js); any other info string renders the body as a flat code run. Prose-length lines soft-wrap instead of scrolling horizontally — the wrap is visual only, so copied text keeps the authored line breaks |
lang-prompt |
AI prompt | Prompt text written to be pasted into a coding agent. Colours the parts the reader must check before sending: paths and filenames, SCREAMING_CASE placeholders and markers, and quoted phrases. Wraps like Markdown |
Built-in Features
HTML, CSS, JavaScript, Markdown, and agent prompts are highlighted automatically. Embedded <style> and <script> bodies inside HTML blocks are highlighted in their respective languages.
Every block gets a CSS counter gutter — no class needed. The gutter is reserved in CSS so it paints before the highlighter loads, and the line digits drop into it without shifting your code. Markdown blocks skip the gutter — their lines soft-wrap, so one digit would sit beside several visual rows.
Each block names its language with an nds-tag in the top corner opposite the action bar, stamped from the authored lang-* class — so it names languages the highlighter doesn't lex too (lang-bash, lang-json). Every block carries one: in a tabbed block the tag sits in each panel, and a block with no lang-* class is named from the sniffed language. To place extra badges beside it, author a .nds-code-tags strip (see Usage Guidelines).
Add nds-copy to any button inside .nds-code-action to copy the block's source text. The component sizes that button itself — nds-icon-only nds-md is stamped at init, so no block needs the classes in its markup; a button carrying a visible label keeps its width. The button shows a brief "Copied" state on success.
When no lang-* class is set, the lexer sniffs the language from the content: leading < implies HTML, JS keywords imply JavaScript, selector or declaration patterns imply CSS. A lang-* class that names a language we don't lex renders as plain text — your label is never overridden by a guess.
Apply nds-inline-code to a <code> element for short inline references. Coloring comes straight from the lang-* class in CSS, so inline code is correct at first paint with no JavaScript.
Six role-named --syntax-* custom properties let you override every syntax color at the page or component level. Each ships a light and a dark value that clears WCAG AA contrast.
Usage Guidelines
Authored Tag Strip
To place extra badges beside the language tag (a version tag, a status chip), author a .nds-code-tags strip as a direct child of the block. The strip replaces the auto-stamped label — the authored .nds-code-lang chip inside it suppresses the stamp — and it carries the block's lang-* class so it clears the line-number gutter the same way the stamped tag would. Extra chips are ordinary nds-tag elements.
<div class="nds-code">
<span class="nds-code-tags lang-html">
<span class="nds-tag nds-gray nds-xs nds-code-lang lang-html"><span class="nds-label">HTML</span></span>
<span class="nds-tag nds-green nds-xs"><span class="nds-label">v3</span></span>
</span>
<div class="nds-code-action">…</div>
<code class="lang-html">…</code>
</div>
Data Attributes
| Attribute | Element | Description |
|---|---|---|
data-nds-code-processed | code | Set to true by JS after highlighting. Guards against double-processing. Set to false by reprocessCodeElement before re-highlighting. |
CSS Custom Properties
These properties apply to both .nds-code and .nds-inline-code. Set them on a parent element or :root to re-theme all code on the page. Each is named for the role it colors, and setting one overrides both light and dark mode.
| Property | Light | Dark | Highlights |
|---|---|---|---|
--syntax-tag | --colors-red-600 | --colors-red-400 | HTML tags and CSS selectors |
--syntax-attr | --colors-yellow-700 | --colors-yellow-400 | Attribute names and numbers |
--syntax-string | --colors-green-700 | --colors-green-400 | Attribute values, strings and template literals |
--syntax-property | --colors-blue-600 | --colors-blue-400 | CSS property names |
--syntax-keyword | --colors-tertiary-500 | --colors-tertiary-300 | Keywords, literals and built-in globals |
--syntax-comment | --colors-neutral-500 | --colors-neutral-400 | Comments |
--code-max-height | 60svh | Height a block scrolls inside instead of growing the page | |
JavaScript API
The NDS.Code API is called automatically on page load. Call NDS.Code.init() after inserting code blocks dynamically.