Vanilla Breeze

Glossary terms in prose

How to link a vocabulary concept inline so the popover enhancement and the glossary page both pick it up. First mention in , subsequent mentions plain.

Why this exists

The site has a single glossary generated from site/src/_data/vocabulary.json. When you mention one of those concepts in article prose, link to it. Two things light up:

  • The glossary page is the canonical anchor (every concept has id="term-{@id}"), so the link is always valid even without JS.
  • A small popover script (/js/definition-popover.js, generated at build) fetches /definitions.json on first interaction and shows the definition in a native popover anchored to the term. Modifier-clicks fall through to the glossary page.

The pattern

Two forms, depending on whether this is the first mention of the concept on the page.

First (defining) use

Wrap the link in <dfn>. The data-concept attribute carries the SKOS @id from vocabulary.json. The href deep-links to the term's anchor on the glossary page so the link is meaningful with no JS.

Subsequent uses

Plain anchor — no <dfn>. <dfn> marks the defining instance; using it on every mention would be wrong semantically and visually noisy.

Rules of thumb

  • Link the concept, not the word. Only link when you genuinely mean the vocabulary entry — not every casual use of the word "review" or "trust".
  • One <dfn> per concept per page. Subsequent mentions on the same page should be plain anchors.
  • Don't link inside a heading. Headings are navigation; the popover would fight with the heading-link affordance. Link from the body prose right after.
  • Don't link inside <code>, <pre>, or another <a>. Code samples carry their own typography contract; nested anchors are invalid HTML.
  • Don't link more than one or two terms per paragraph. The dotted-underline cue is helpful in moderation; turn into noise quickly.
  • Add the concept to the page's frontmatter. If the page is about the concept, list it in concepts: [...]. The meta-tag contract already emits <meta name="concept"> + <link rel="tag"> + <link rel="glossary"> automatically.

How to find the right @id

Open site/src/_data/vocabulary.json and search for the concept's pref-label. The @id is the slug-form (e.g. "meta-tag-contract", "data-provenance", "page-info"). The href is always /glossary/#term-{@id} — that's what the build emits and what the popover script expects.

If the concept isn't in the vocabulary yet but should be, add it to vocabulary.json first (see the SKOS shape used by sibling entries) and re-run npm run build. The glossary page, /definitions.json, and head metadata regenerate from that single source.

What the popover does (and doesn't)

  • Feature-detects the Popover API; on browsers without it, every link is a normal navigation to the glossary anchor. Same accessibility either way.
  • Caches /definitions.json in sessionStorage under vb:definitions. One fetch per browsing session.
  • Respects Cmd / Ctrl / Shift / Alt / middle-click — those open the glossary page like any other link.
  • Native popover handles Escape and light-dismiss. We don't reimplement focus management.

See also