Skip to content

Term

A word in running text, linked to its entry in a glossary further down the page. Without JavaScript the word is a link, and a click goes to the glossary. With <lt-term> around the link, the entry opens as a card by the word, and the reader keeps their place.

The card is the glossary entry itself, not a copy. The web component sets popover="manual" on the entry while the card is open, so the entry goes into the top layer by the word, and takes the attribute off again when it closes. The server sends the explanation once, the links in it are the real ones, and an update from the server that morphs the glossary leaves the card standing.

It is not a Tooltip. A tooltip must never carry information the reader needs, and it does not open on a touch screen. An explanation is information the reader needs, and the card opens on a tap. It is closest to Popover, but it opens from a word in the text rather than a button, and its content is somewhere else on the page.

// main.ts, runs once when the app starts
import { defineLtTerm } from "@lo-tek/interfaces/term"
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/term.css"
defineLtTerm()

Rest the mouse on a word with a dotted line, or click it. A click pins the card, so it stays until Escape, a click outside or another click on the word.

const actOfGod = lt.term({ id: "term-act-of-god" })
<lt-term>
<a class="lt-term" href="#term-act-of-god" aria-details="term-act-of-god">act of God</a>
</lt-term>
<dl>
<div class="lt-term__entry" id="term-act-of-god">
<dt>Act of God</dt>
<dd>A cause of death the policy does not cover.</dd>
</div>
</dl>

lt.term({ id }) writes only what holds without JavaScript: href and aria-details on the link, and the id on the entry. The id is required, and an empty one throws: a made-up id would point at nothing, since only the template knows the entry’s. Make it from the term, such as term-act-of-god, never from a counter.

The web component finds the link as the first <a> with an href to a fragment, and the entry by the id in it, anywhere in the same document or shadow root. The entry must be a <div> in a <dl> with a <dt> and a <dd>, the form HTML has for grouping a term with its description. If the id does not exist, or points at something else, such as the <dt>, the word stays a plain link, and the web component says so in the console. The check says so too (term-without-entry), but only for a whole page, with lotek check --rendered or an address: in a template the glossary can be in another file.

Several words can point at the same entry. Only one card can be open, so the word that opens it takes it from the other.

InputWhat happens
The mouse rests on the wordThe card opens after 300 ms. It closes when the pointer leaves the word, unless the pointer goes into the card, where the reader can select text and follow links
A click, a tap or EnterThe card opens and is pinned. Leaving with the mouse does not close it
A click on the word when the card is pinnedThe card closes
A click with Cmd, Ctrl, Shift or AltLeft to the browser: a new tab or window to the glossary
EscapeThe card closes, and focus goes back to the word
A click outsideThe card closes
The word scrolls out of viewThe card closes. Scrolling a little moves the card with the word

Opening, closing and moving focus never scroll the page, and the address does not change.

Below 640 pixels, the sm breakpoint, the card is a sheet across the width of the window. It stands at the bottom, where the thumb is, and at the top when the word is so far down that the sheet would cover it. The word whose card is open is marked, so the reader sees what the sheet belongs to. A card next to the word covered the lines the reader was about to read.

The sheet is at most 60 % of the window high, and a longer explanation scrolls inside it. A tap outside or on the word closes it. The width is fixed in the stylesheet, since a media query cannot read a variable.

While the card is open, the entry is not in its place in the glossary. Put the glossary after the text that uses it: then nothing above the word moves when the card opens. A glossary that stands in view next to the word closes up where the entry was for as long as the card is open.

ClassWhat it is
.lt-termThe word, a link with a dotted line under it. The web component sets the class when it is missing
.lt-term__entryThe glossary entry. Its look as a card applies only while it is open, so it looks as the page made it in the glossary
VariableDefault
--lt-term-widthmin(22rem, calc(100vw - var(--lt-spacing-8))), the maximum width of the card
--lt-term-gapvar(--lt-spacing-2), the space between the word and the card
--lt-term-sheet-height60dvh, the maximum height of the sheet on a narrow screen
--lt-term-paddingvar(--lt-spacing-3) var(--lt-spacing-4)
--lt-term-radiusvar(--lt-spacing-1)
--lt-term-accent-colorvar(--lt-color-accent-fill), the edge at the start of the card
--lt-term-underline-colorvar(--lt-color-accent-fill), the dotted line under the word
--lt-term-label-text"Glossary", the label over the term in the card
--lt-term-label-fontinherit, the font of the label
--lt-term-topset by the web component
--lt-term-leftset by the web component

The position is set as --lt-term-top and --lt-term-left on the entry while the card is open, and removed when it closes.

See Customising for how the variables and the layer work.

What a screen reader is given when the recipe above is used, step by step. It is checked through AT-SPI, the interface Orca reads, in Chromium and Firefox, on every change, by check-accessibility-tree.ts, and every change the check lists as a mutation must make it fail.

  1. Focus lt-term > a: focus on the link "act of God", expandable, not expanded.
  2. Press Enter: focus on the link "act of God", expanded; the change to expanded sent as an event.
  3. Press Escape: focus on the link "act of God", not expanded.
  • The word stays a link, so it is announced as one, and it can still be opened in a new tab. aria-details points at the entry, and screen readers that support it say the link has details. aria-expanded says whether the card is open.
  • The entry is in the glossary whether the card is open or not, so aria-details never points at something empty, and the explanation can be read there too.
  • The card does not take focus, and a keyboard user reaches the links in it in the glossary. Escape closes it from anywhere on the page.
  • Content that appears on hover can be dismissed with Escape, stays while the pointer is over it, and stays until the reader moves on, as WCAG 1.4.13 requires.