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 — a :term: link inside a popover opens a second-level popover (capped at two levels, configurable).

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), 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. 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 keep popover-internal :term: links inert.

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-1.3.1.tar.gz (40.1 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-1.3.1-py3-none-any.whl (47.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sphinx_riddle_whisper-1.3.1.tar.gz
  • Upload date:
  • Size: 40.1 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-1.3.1.tar.gz
Algorithm Hash digest
SHA256 df96aef4368740fa29ee2988c1f47d738f3744992b1ee75a185846e57f7e6efb
MD5 10361c0a7fa199815bf59aaa362f4fbb
BLAKE2b-256 b5fbd614764149ea988521ed81b9ec4914a855ab5938bf5e158d20f1c6d7d547

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinx_riddle_whisper-1.3.1.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-1.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sphinx_riddle_whisper-1.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 57479374457f209878ef9dea04073aab4d9b2879d144aa0c1243cc03276404c3
MD5 fa6523e6417f9d2395a6e5b16eb552d6
BLAKE2b-256 37e7b40251c6f25eb176ff1f531f566ca138c3a63ec645f04ffe1d811529f25e

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinx_riddle_whisper-1.3.1-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