Sphinx extension that shows full glossary term definitions in a popup (no truncation, offline, vanilla JS).
Project description
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.
Requirements
Python >= 3.14
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. |
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
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.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sphinx_riddle_whisper-0.1.1.tar.gz.
File metadata
- Download URL: sphinx_riddle_whisper-0.1.1.tar.gz
- Upload date:
- Size: 33.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84d8f0dc79b9bd2fc892703b2258a5aba38631923c6c7f02fd2a2d5ffa2ea41f
|
|
| MD5 |
8f10e21fee146959fe2b637bf5d499fd
|
|
| BLAKE2b-256 |
db6d82b275de2a33d8902a9cdbce72be004e05bde3e5dd4f1480aaa5bdbb77f3
|
Provenance
The following attestation bundles were made for sphinx_riddle_whisper-0.1.1.tar.gz:
Publisher:
publish-to-pypi.yml on usaturn/sphinx-riddle-whisper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sphinx_riddle_whisper-0.1.1.tar.gz -
Subject digest:
84d8f0dc79b9bd2fc892703b2258a5aba38631923c6c7f02fd2a2d5ffa2ea41f - Sigstore transparency entry: 1941001039
- Sigstore integration time:
-
Permalink:
usaturn/sphinx-riddle-whisper@44475b29ce65621c0b4b2f7a5e81b755c3fe580f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/usaturn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@44475b29ce65621c0b4b2f7a5e81b755c3fe580f -
Trigger Event:
push
-
Statement type:
File details
Details for the file sphinx_riddle_whisper-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sphinx_riddle_whisper-0.1.1-py3-none-any.whl
- Upload date:
- Size: 40.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc8e1256137aede5da0d34fd999395a2be3e9fd8ba2c95835ad8dfd118da3906
|
|
| MD5 |
c1a083f778016e855d975141c96aca49
|
|
| BLAKE2b-256 |
5874b34624841d9db51fc14028318eed16beaa5faed767e0028b7c988c9e8ede
|
Provenance
The following attestation bundles were made for sphinx_riddle_whisper-0.1.1-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on usaturn/sphinx-riddle-whisper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sphinx_riddle_whisper-0.1.1-py3-none-any.whl -
Subject digest:
cc8e1256137aede5da0d34fd999395a2be3e9fd8ba2c95835ad8dfd118da3906 - Sigstore transparency entry: 1941001091
- Sigstore integration time:
-
Permalink:
usaturn/sphinx-riddle-whisper@44475b29ce65621c0b4b2f7a5e81b755c3fe580f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/usaturn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@44475b29ce65621c0b4b2f7a5e81b755c3fe580f -
Trigger Event:
push
-
Statement type: