Skip to main content

Sphinx extension that shows full glossary term definitions in a popup (no truncation, offline, vanilla JS).

Project description

PyPI Python versions License: MIT 日本語

A Sphinx extension that shows full glossary term definitions in a popup — no truncation, offline, vanilla JS.

When a reader hovers or clicks a :term: reference, the complete glossary definition appears in a popover right where they are reading, so they never have to jump to the glossary page and back.

Features

  • No truncation — the full glossary definition is shown, with a configurable max height/width and scrolling for long entries.

  • Offline — definitions are rendered at build time and injected as inline <template> elements. No network requests, no CDN.

  • Vanilla JS — no third-party runtime libraries are bundled.

  • Hover and click — open popovers on hover, click, or both.

  • Footnotes & citations — optionally show footnote and citation bodies in the same popover style.

  • Image lightbox — optionally open linked images in a focus-trapped lightbox.

  • Layered sanitization — HTML is sanitized with nh3 at build time and re-checked in the browser as a second line of defense.

  • Incremental build aware — pages that reference a term are rebuilt when the term’s home definition changes.

  • Nested popovers — hovering (or focusing) a :term: link inside a popover opens a second-level popover (capped at two levels, configurable); clicking it opens the glossary in a new tab instead.

  • New-tab links — links inside a popover open in a new browser tab with rel="noopener noreferrer" (image links keep the lightbox behavior while the image lightbox is enabled).

Requirements

  • Python >= 3.11

  • Sphinx >= 9

Installation

From PyPI:

pip install sphinx-riddle-whisper

From source:

pip install git+https://github.com/usaturn/sphinx-riddle-whisper.git

Or clone and install locally (this project uses uv):

git clone https://github.com/usaturn/sphinx-riddle-whisper.git
cd sphinx-riddle-whisper
uv pip install .

Quick Start

Add the extension to your conf.py:

extensions = ["sphinx_riddle_whisper"]

Define your terms with the standard glossary directive:

.. glossary::

   reStructuredText
       A plain-text markup syntax and parser system, and the default
       markup language used by Sphinx.

Then reference them from any page with the :term: role:

Sphinx documents are usually written in :term:`reStructuredText`.

Build your HTML as usual. Hovering or clicking the :term: reference now opens a popover containing the full definition — no extra markup required.

Configuration

All options are set in conf.py. The display and feature options and their defaults are:

Option

Type

Default

Description

riddle_trigger

str

"both"

How popovers open: "hover", "click", or "both".

riddle_max_height

str

"24rem"

Maximum popover height (any CSS length).

riddle_max_width

str

"32rem"

Maximum popover width (any CSS length).

riddle_open_delay_ms

int

150

Delay before opening on hover, in milliseconds (>= 0).

riddle_close_delay_ms

int

100

Delay before closing on hover-out, in milliseconds (>= 0).

riddle_interactive

bool

True

Keep the popover open while the pointer is over it.

riddle_include_term_title

bool

True

Show the term name as a heading at the top of the popover.

riddle_footnotes

bool

True

Enable popovers for footnote and citation references.

riddle_image_popup

bool

True

Enable the image lightbox.

riddle_nested

bool

True

Open a second, nested popover from :term: links inside a popover.

riddle_mark_terms

bool

True

Visually mark :term: links that pop up (dotted underline + help cursor).

riddle_table_align

str

"left"

Alignment of tables inside popovers: "left", "center", or "right".

Example showing the defaults:

riddle_trigger = "both"
riddle_max_height = "24rem"
riddle_max_width = "32rem"
riddle_open_delay_ms = 150
riddle_close_delay_ms = 100
riddle_interactive = True
riddle_include_term_title = True
riddle_footnotes = True
riddle_image_popup = True
riddle_nested = True
riddle_mark_terms = True
riddle_table_align = "left"

Footnotes, Citations & Image Lightbox

With riddle_footnotes = True (the default), footnote and citation references open a popover containing the footnote or citation body, drawn from the same page — so readers can check a reference without losing their place.

With riddle_image_popup = True (the default), a linked image opens in a focus-trapped, scroll-locked lightbox. Only safe image URLs (recognized image extensions over allowed schemes) are opened.

Set either option to False to disable that feature.

Nested Popovers

With riddle_nested = True (the default), hovering or focusing a :term: link inside an open popover opens a second, nested popover on top of the first, so definitions that reference other terms can be explored without leaving the page. Clicking such a link opens the glossary in a new browser tab instead. Nesting is capped at two levels — :term: links inside the second popover behave as normal links — and a link pointing to the term already shown in the first popover does not open a duplicate. Press Esc to close the inner popover first, then the outer one. Set the option to False to disable nesting; popover-internal :term: links then behave like any other popover link and open the glossary in a new tab. With riddle_trigger = "click", nested popovers are not reachable; popover-internal :term: links simply open the glossary in a new tab.

Table Alignment Inside Popovers

Sphinx renders tables without an explicit :align: option with the align-default class, which most themes center. Inside the narrow popover this looks odd, so such tables are left-aligned by default. Set riddle_table_align to "center" or "right" to change this. Tables with an explicit :align: option keep their author-specified alignment, and the setting also applies to tables inside footnote and citation popovers.

Security

Glossary definitions can contain arbitrary inline HTML, so the extension sanitizes content in two layers:

  • Build time — definition fragments are sanitized with nh3 against a built-in allowlist of tags, attributes, and URL schemes before being injected.

  • Runtime — before a popover is shown, the cloned fragment is walked again in the browser: elements outside the allowlist are removed, on* handlers and dangerous URL schemes are stripped, and target="_blank" links get rel="noopener noreferrer".

The safety-related options let you tune or replace the build-time allowlist:

Option

Type

Default

Description

riddle_sanitize

bool

True

Enable build-time HTML sanitization with nh3.

riddle_allowed_tags

tuple[str] | None

None

Allowed HTML tags. None uses the built-in allowlist.

riddle_allowed_attributes

dict[str, tuple[str]] | None

None

Allowed attributes per tag. None uses the built-in allowlist.

riddle_allowed_schemes

tuple[str] | None

None

Allowed URL schemes. None uses the built-in allowlist.

riddle_strip_classes

tuple[str]

("headerlink", "sd-stretched-link")

CSS class names whose anchors are removed from the definition.

Documentation

The full documentation is built with Sphinx from the docs/ directory of this repository.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sphinx_riddle_whisper-2.0.0.tar.gz (41.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sphinx_riddle_whisper-2.0.0-py3-none-any.whl (48.7 kB view details)

Uploaded Python 3

File details

Details for the file sphinx_riddle_whisper-2.0.0.tar.gz.

File metadata

  • Download URL: sphinx_riddle_whisper-2.0.0.tar.gz
  • Upload date:
  • Size: 41.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for sphinx_riddle_whisper-2.0.0.tar.gz
Algorithm Hash digest
SHA256 9b93cfa71f31e1398475a031d1b6c087f15debd1e39e214a66a2a65a5d44c51d
MD5 ffe9f000e73722ee965861f95cb942c3
BLAKE2b-256 b4eb8b9f15fc58f51e90b622af99eb1c5ab39efac9d5ae58e7d27489c63f7977

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinx_riddle_whisper-2.0.0.tar.gz:

Publisher: publish-to-pypi.yml on usaturn/sphinx-riddle-whisper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sphinx_riddle_whisper-2.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sphinx_riddle_whisper-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 42e0667773c7ffd97d57b565fb90d9daf2c80919e2cffc82cd1c28c9018e9488
MD5 950ef80300c8a01b5b2c5bdb6d04fbfc
BLAKE2b-256 9864688d6d6a46f016da4621d71a84e1f078e9e96f2eddde7a98dd61e2776116

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinx_riddle_whisper-2.0.0-py3-none-any.whl:

Publisher: publish-to-pypi.yml on usaturn/sphinx-riddle-whisper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page