[FEATURE] artifact-design: add a "Glossary sidebar" pattern (collapsible, category-filterable, main-column-only scroll)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 28, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request

Problem Statement

The artifact-design skill has no guidance for jargon-dense explainer artifacts — protocol comparisons, architecture decision records, security write-ups, RFC summaries. These pages are exactly the kind of thing Claude Code gets asked to publish after a deep investigation, and they are unreadable to anyone who isn't already fluent in the terminology.

Today Claude has two bad options and picks one at random:

  1. Inline definitions in prose. Every occurrence of code_verifier gets a parenthetical. The document bloats, and readers who already know the term wade through noise.
  2. A glossary section at the bottom. The reader has to scroll away from the diagram they're trying to understand, find the term, and scroll back — losing their place every time. On a long page this is the difference between reading the artifact and giving up on it.

Neither is discoverable, neither is filterable, and neither survives the reader's actual workflow of "what does this word mean, in the middle of this paragraph."

Separately, the layout technique that makes option 3 work (main column scrolls, sidebar stays pinned) is a documented CSS trap, and Claude gets it wrong without explicit instruction — see Additional Context.

Proposed Solution

Add a Glossary sidebar pattern to artifact-design, alongside the existing structural guidance, with three properties:

1. Only the main content scrolls. Above a breakpoint (~1040px), the page becomes a fixed-height two-column shell. The reader can page through the body without the glossary moving. Below the breakpoint it degrades to a normal stacked section — never a floating overlay on mobile.

@media (min-width: 1040px) {
  body { overflow: hidden; }

  /* 100vh rather than a height:100% chain, so this does not silently
     collapse if the host wrapper leaves html/body auto-height. */
  .plate  { height: 100vh; padding-top: 0; padding-bottom: 0; }
  .layout { height: 100%; }

  .col-main {
    min-height: 0;                  /* required, or the column never scrolls */
    overflow-y: auto;
    overscroll-behavior: contain;   /* scroll does not chain to the host page */
  }
}

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--aside-w, 22rem);
  /* A single row that fills the container. Without this the row is
     content-sized, the main column has no constrained height, and
     nothing can scroll inside it. */
  grid-template-rows: minmax(0, 1fr);
}

2. Collapsible. The sidebar collapses to a ~3rem vertical rail so the reader can reclaim the width for a wide diagram or table, and the choice persists across visits:

.layout[data-aside="closed"] { --aside-w: 3rem; }
.layout[data-aside="closed"] .aside-inner { display: none; }
.layout[data-aside="open"]   .rail        { display: none; }
function setAside(state, moveFocus) {
  layout.dataset.aside = state;
  const open = state === "open";
  railOpen.setAttribute("aria-expanded", String(open));
  glossCollapse.setAttribute("aria-expanded", String(open));
  try { localStorage.setItem("glossary-aside", state); }
  catch { /* private window or blocked site data — the default is fine */ }
  if (moveFocus) {
    const target = open ? glossCollapse : railOpen;
    // offsetParent is null below the breakpoint, where neither control is shown.
    if (target.offsetParent !== null) target.focus();
  }
}

This matches the skill's existing localStorage guidance exactly: a per-viewer convenience, wrapped in try/catch, correct with no stored value.

3. Searchable and filterable by category. Terms are data, not markup — an array of [term, category, definition] rendered by one function, with a text filter, category chips, and a live N of M count:

const TERMS = [
  ["code_verifier", "pkce",   "A high-entropy random string the client keeps to itself…"],
  ["device_code",   "device", "The client's opaque polling handle…"],
  ["Refresh token", "both",   "A longer-lived credential exchanged for new access tokens…"],
];

function renderGlossary() {
  const q = glossSearch.value.trim().toLowerCase();
  const shown = TERMS.filter(([term, tag, def]) => {
    if (glossTag !== "all" && tag !== glossTag) return false;
    if (!q) return true;
    return (term + " " + def).toLowerCase().includes(q);
  });
  // …render, then:
  glossCount.textContent = `${shown.length} of ${TERMS.length}`;
}

The categories carry meaning in a comparison document — pkce / device / both immediately tells the reader which half of the argument a term belongs to, and chip colors tie back to the accent colors used in the body.

When to reach for it (the part that most needs to be in the skill): a reference or explainer page carrying ~15+ domain terms the reader may not know. Not a short memo, not a dashboard, not a page with five pieces of jargon — those are better served by inline definitions. The skill should say this, so the pattern doesn't get over-applied.

Alternative Solutions

  • <abbr title> / hover tooltips. No touch support, not searchable, invisible until hovered.
  • <details> inline after each term. Interrupts the prose flow and repeats the definition at every occurrence.
  • Glossary at the bottom + anchor links. Cheapest option, but it destroys the reader's scroll position — which is the actual problem.
  • Leave it to the model. Current state. Claude sometimes builds something like this unprompted, but the fixed-height scroll shell is a genuine CSS trap (see below), so the unprompted version is often subtly broken.

Priority

Medium

Feature Category

Skills / Artifacts

Use Case Example

A device-code vs PKCE OAuth security write-up published as an artifact, carrying ~31 terms across three categories (PKCE, Device, Both). Reading it means holding code_verifier, code_challenge, S256, device_code, user_code, authorization_pending and slow_down in your head at once, while following a stepped sequence diagram in the main column.

With the pattern: the diagram stays put, the glossary stays put, typing refresh in the filter narrows 31 terms to 3 without ever leaving the paragraph you were on, and hitting Device shows only the half of the vocabulary that belongs to the grant being criticized. Without it, every unfamiliar term costs a round trip to the bottom of the page.

The same shape covers architecture decision records, incident post-mortems, migration guides, protocol/spec summaries, and internal onboarding docs — all common artifact requests from Claude Code.

Additional Context

The scroll shell is the part that needs to be written down. Three separate non-obvious requirements, any one of which silently produces a page where nothing scrolls or the whole viewport scrolls:

  1. grid-template-rows: minmax(0, 1fr) on the grid — without it the row is content-sized and the main column has no constrained height to scroll within.
  2. min-height: 0 on the scrolling child — the grid/flex default of auto refuses to shrink below content size.
  3. height: 100vh on the outer wrapper rather than a height: 100% chain — the artifact host does not guarantee html/body height, so the chain collapses.

Plus overscroll-behavior: contain so reaching the end of the column doesn't scroll the embedding page.

Accessibility details worth codifying: aria-expanded + aria-controls on both the collapse button and the rail, focus moved to whichever control is now visible, offsetParent checked before focusing (both controls are hidden below the breakpoint), aria-pressed on the filter chips, <dl> / <dt> / <dd> for the term list, and <input type="search"> with an aria-label.

Theming: chips and category tags need their accent colors defined on bare :root and redefined under both @media (prefers-color-scheme: dark) and :root[data-theme="dark"], per the skill's existing three-state theme rule. A glossary is dense with small colored labels, so this is where a partial dark-mode palette shows up worst.

I have a working reference implementation of all of the above if it would be useful for the skill's examples.

View original on GitHub ↗