Skip to content

Inline definition (contextual term explainer)

components specs/components/inline-definition.kmd

Underlined term that, on hover / focus / tap, surfaces its definition in a popover without navigating away. Useful in jargon-dense surfaces (Koda lang docs, AI surfaces explaining "context window" / "tokens"). Modeled after MongoDB LeafyGreen InlineDefinition.

When this spec applies

Primary triggers

All triggers

Specification body

Component — Inline definition

Status: v0.1.0 — Draft.

R1 — Anatomy

  • Term rendered inline in body text with a 1px dotted underline (text-decoration: underline dotted currentColor).
  • On trigger: floating popover with:
    • Term (bold).
    • 1–3 short lines of definition.
    • Optional "Learn more" link (single, never multiple actions).

R2 — Trigger

SurfaceTrigger
Desktop / mouseHover (200ms delay)
KeyboardFocus (Tab to term)
TouchTap (toggle)

Dismisses on:

  • Pointer leave (desktop)
  • Blur (keyboard)
  • Outside-tap (touch)
  • Esc (any modality)

R3 — Semantic HTML

  • Wrap term in <dfn> element — the HTML element specifically for "defining instance of a term".
  • <dfn> made focusable via tabindex="0" so keyboard users can trigger.
  • Popover: role="tooltip" with aria-labelledby (term id) and id referenced by <dfn>'s aria-describedby.

R4 — Accessibility

  • Definition content also rendered in DOM (visually hidden) immediately after the term so screen-readers receive it without firing visual hover.
  • For non-sighted users, <dfn> carries title attr with the definition as fallback if popover JS doesn't load.

R5 — Density limits

  • Author SHOULD use sparingly — no more than 1 inline definition per short paragraph (≤ 3 sentences).
  • If a paragraph needs 3+ defined terms, switch to a sidebar glossary or a parenthetical inline gloss.

R6 — i18n

  • Both term and definition translatable per specs/i18n/contract.kmd.
  • Definitions stored with a stable key (term.<slug>.definition) so the same definition can be reused across pages.

R7 — OUIA

Per specs/testing/ouia-test-hooks.kmd:

  • data-ouia-component-type="InlineDefinition"
  • data-ouia-component-id="<term-slug>" (defaults to slugified term).
  • data-ouia-safe="true" always.

Não-escopo

  • Auto-link to a separate glossary page (out of v0; the popover is the glossary entry).
  • Definition versioning / per-tenant override (specialized scope).

Requirements (testable)

Requirement: Inline term renders with dotted underline and popover content {#req-inline-def-anatomy}

The component SHALL render the defined term inline in body text with a 1px dotted underline (text-decoration: underline dotted currentColor), and on trigger SHALL surface a floating popover containing the bold term, one to three short lines of definition, and at most one optional "Learn more" link (never multiple actions).

Scenario: Term is underlined in flowing body copy

  • GIVEN a paragraph of body text containing one defined term
  • WHEN the surface renders
  • THEN the term's computed style has text-decoration-line: underline AND text-decoration-style: dotted
  • AND the underline color resolves to currentColor

Scenario: Popover shows term, definition, and single optional action

  • GIVEN a defined term configured with a definition and a "Learn more" link
  • WHEN the popover is triggered
  • THEN the popover displays the term rendered bold
  • AND the popover displays between one and three lines of definition text
  • AND the popover contains at most one action link

Requirement: Trigger and dismissal follow the input modality {#req-inline-def-trigger}

The component SHALL open the definition popover on hover with a 200ms delay for pointer input, on focus for keyboard input, and on tap for touch input; and it SHALL dismiss the popover on pointer-leave, blur, outside-tap, or the Esc key according to the active modality.

Scenario: Pointer hover opens after delay and closes on leave

  • GIVEN a defined term on a desktop pointer surface
  • WHEN the pointer hovers over the term for 200ms
  • THEN the popover becomes visible
  • WHEN the pointer subsequently leaves the term
  • THEN the popover is dismissed

Scenario: Esc dismisses the popover in any modality

  • GIVEN a defined term whose popover is currently open
  • WHEN the Esc key is pressed
  • THEN the popover is dismissed

Scenario: Touch tap toggles the popover

  • GIVEN a defined term on a touch surface with its popover closed
  • WHEN the term is tapped
  • THEN the popover becomes visible
  • WHEN a tap occurs outside the popover
  • THEN the popover is dismissed

Requirement: Term uses semantic dfn element with wired ARIA relationships {#req-inline-def-semantics}

The component SHALL wrap the defined term in a <dfn> element made focusable via tabindex="0", and the popover SHALL carry role="tooltip" with aria-labelledby referencing the term id while the <dfn> references the popover via aria-describedby.

Scenario: dfn is keyboard-focusable and describes the popover

  • GIVEN a defined term rendered in the DOM
  • WHEN the DOM is inspected
  • THEN the term is a <dfn> element carrying tabindex="0"
  • AND the <dfn> has an aria-describedby whose value equals the popover element's id

Scenario: Popover is labelled by the term

  • GIVEN a defined term whose popover is present in the DOM
  • WHEN the popover element is inspected
  • THEN it has role="tooltip"
  • AND its aria-labelledby references the id of the term element

Requirement: Definition is exposed to assistive technology without visual hover {#req-inline-def-a11y}

The component SHALL also render the definition content in the DOM (visually hidden) immediately after the term so screen readers receive it without firing the visual hover, and the <dfn> SHALL carry a title attribute holding the definition as a fallback when popover JavaScript does not load.

Scenario: Visually hidden definition follows the term for screen readers

  • GIVEN a defined term rendered on the page
  • WHEN the DOM immediately following the term is inspected
  • THEN a visually-hidden node containing the full definition text is present
  • AND that node is neither aria-hidden="true" nor display:none, so it remains in the accessibility tree

Scenario: title attribute provides no-JS fallback

  • GIVEN the surface loads without the popover JavaScript executing
  • WHEN the <dfn> term is inspected
  • THEN its title attribute equals the definition text

Requirement: Component exposes stable OUIA test hooks {#req-inline-def-ouia}

The component SHALL emit the OUIA attributes per specs/testing/ouia-test-hooks.kmd: data-ouia-component-type="InlineDefinition", data-ouia-component-id defaulting to the slugified term, and data-ouia-safe="true" always.

Scenario: OUIA attributes are present with defaulted id

  • GIVEN a defined term with the display text "Context window" and no explicit OUIA id
  • WHEN the rendered element is inspected
  • THEN it has data-ouia-component-type="InlineDefinition"
  • AND it has data-ouia-component-id="context-window"
  • AND it has data-ouia-safe="true"

References