Anatomy

Three elements compose a full code sample:

<div class="code-sample" data-lang="html">
  <button class="code-copy-btn" type="button" data-copy>Copy</button>
  <pre class="code-block"><code class="language-html">
    <!-- your escaped HTML here -->
  </code></pre>
</div>

HTML

Set data-lang="html" and class="language-html" on the inner <code>.

<div class="wm-card card" style="padding: 1rem;">
  <h3>Card Title</h3>
  <p>Card body text.</p>
</div>

JavaScript

Use data-lang="js" and class="language-js" (or language-javascript).

const saved = localStorage.getItem('wm-showcase-theme');
if (saved === 'dark') {
  document.documentElement.setAttribute('data-theme', 'dark');
}

CSS

Use data-lang="css" and class="language-css".

:root {
  --wm-color-accent: #3b82f6;
  --wm-radius-md: 0.5rem;
}

[data-theme="dark"] {
  --wm-color-bg: #141414;
  --wm-color-surface: #1a1a1a;
}

Bash / Shell

Use data-lang="bash" and class="language-bash".

npm install @wintermuted/ui-theme
# or
yarn add @wintermuted/ui-theme

Mermaid Diagrams

Mermaid usage now has a dedicated component page with setup guidance, rendering examples, and docs patterns.

Open Mermaid component docs


Copy Button Behavior

The .code-copy-btn element requires a data-copy attribute to be wired by showcase.js. On click, the script reads pre.textContent.trim() (post-Prism tokenization) and calls navigator.clipboard.writeText(). The button label changes to "Copied!" for 1.5 seconds, then resets.

The copy button is always visible — positioned absolutely in the header bar. No hover required.

// showcase.js — wireCopyButtons()
document.querySelectorAll('[data-copy]').forEach((btn) => {
  btn.addEventListener('click', () => {
    const pre = btn.closest('.code-sample').querySelector('pre');
    navigator.clipboard.writeText(pre.textContent.trim()).then(() => {
      btn.textContent = 'Copied!';
      setTimeout(() => (btn.textContent = 'Copy'), 1500);
    });
  });
});

Header Bar via CSS

The language label in the header bar is generated entirely in CSS using the ::before pseudo-element and the attr() function. No JavaScript reads the data-lang attribute — the label is purely decorative metadata for the reader.

/* showcase.css */
.code-sample {
  position: relative;
}

.code-sample::before {
  content: attr(data-lang);
  display: flex;
  align-items: center;
  height: 2rem;
  padding: 0 0.75rem;
  background: var(--wm-color-surface-strong);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--wm-color-text-muted);
}

Prism.js Integration

Syntax highlighting is handled by Prism.js 1.29.0 loaded from CDN. Include the core script, autoloader plugin, and a theme CSS before your page scripts. The autoloader fetches language grammar files on demand based on the class="language-*" attribute.

<!-- In <head> -->
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"
  crossorigin
/>

<!-- Before closing </body> -->
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"
  crossorigin
></script>
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"
  crossorigin
></script>
// Configure autoloader path and trigger highlight
if (typeof Prism !== 'undefined') {
  Prism.plugins.autoloader.languages_path =
    'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/';
  Prism.highlightAll();
}