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
- Add inline term-definitions to a docs / chat / canvas surface
All triggers
- Render a glossary term inline in body copy
- Annotate a technical term with a brief contextual definition
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
| Surface | Trigger |
|---|---|
| Desktop / mouse | Hover (200ms delay) |
| Keyboard | Focus (Tab to term) |
| Touch | Tap (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 viatabindex="0"so keyboard users can trigger.- Popover:
role="tooltip"witharia-labelledby(term id) andidreferenced by<dfn>'saria-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>carriestitleattr 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: underlineANDtext-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 carryingtabindex="0" - AND the
<dfn>has anaria-describedbywhose value equals the popover element'sid
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-labelledbyreferences 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"nordisplay: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
titleattribute 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
specs/components/info-sprinkle.kmdspecs/components/guide-cue.kmd