A small, dependency-free script that drops a What's new? trigger into your product and opens your Jamdesk changelog in a modal, with a per-visitor unread dot. One <script> tag, no build step, ~16 KB.
This repository is the source and the version history for that script. Most customers never need it: the Jamdesk dashboard generates a ready-to-paste snippet, and Jamdesk hosts and updates the widget for you. The repo exists for two cases — pinning a specific version, and self-hosting the file from your own origin.
📖 Full guide: Embed Your Changelog on the Jamdesk docs covers every option, CSP setup, and the unread-dot behavior in depth. Start there. This README is the quick reference plus the distribution details.
Open your dashboard, go to Settings → What's New widget, set the page and launcher options, and copy the snippet. It points at your own *.jamdesk.app origin:
<script
src="https://acme.jamdesk.app/_jd/widget.js"
data-base="https://acme.jamdesk.app"
data-page="/changelog"
data-theme="auto"
async
></script>Paste it before your closing </body> tag. Jamdesk keeps this copy current, so you get fixes and new options without touching the tag. For almost everyone, that's the right choice.
Want the bytes frozen at a known version, immune to future changes? Load the file from jsDelivr at a tagged release:
<script
src="https://cdn.jsdelivr.net/gh/jamdesk/jamdesk-widget@v1.0.0/widget.js"
integrity="sha384-dyQB+8eiu83lzWIrbD9ovoUqXRtzHa0UKMjyKtGFfcIXxQWrqYPvMPgNEjT9fnow"
crossorigin="anonymous"
data-base="https://acme.jamdesk.app"
data-page="/changelog"
data-theme="auto"
async
></script>Swap @v1.0.0 for any released tag. @latest tracks the newest release; a pinned tag never moves.
The integrity hash above is the sha384 Subresource Integrity digest of the v1.0.0 widget.js. With it, the browser refuses to run the file if a single byte differs from what you pinned, so a compromised CDN can't swap in other code. Each release lists its own hash; drop the integrity/crossorigin pair if you'd rather not pin bytes. (Option 1's hosted copy is meant to update in place, so it carries no SRI.)
Download widget.js from the latest release (or this repo) and serve it from your own origin or CDN. Useful when a strict script-src policy rules out third-party scripts:
<script
src="/assets/jamdesk-widget.js"
data-base="https://acme.jamdesk.app"
data-page="/changelog"
async
></script>Important
With jsDelivr or self-hosting, data-base is required. When the script loads from your own *.jamdesk.app origin (Option 1), it figures out where to fetch the changelog from on its own. Loaded from a CDN or your assets folder, it can't — so you must point data-base at your *.jamdesk.app origin (add /docs if you host docs under a subpath). The modal and the unread-dot fetch both target that origin no matter where the script itself came from.
Every option is a data- attribute on the script tag. Only data-base is required outside Option 1.
| Attribute | Values | Default | Purpose |
|---|---|---|---|
data-base |
Your site URL | script origin | Your *.jamdesk.app origin (plus /docs if docs live under a subpath). Required for CDN/self-host. |
data-page |
Path | /changelog |
Which docs path opens in the modal. Any page works, not just the changelog. |
data-theme |
auto, light, dark |
auto |
Force the modal's color scheme or follow the visitor's system setting. |
data-position |
bottom-right, bottom-left, top-right, top-left |
bottom-right |
Corner for the floating launcher. Ignored with data-trigger. |
data-label |
Text | What's new |
The floating launcher's text. |
data-width |
CSS length | 560px |
Modal width. Capped at 92vw so it fits a phone. |
data-height |
CSS length | 680px |
Modal height. Capped at 86vh. |
data-radius |
CSS length | 12px |
Modal corner radius. |
data-unread |
off to disable |
on | Show the unread dot. |
data-unread-color |
Hex or CSS color | #e5484d |
Unread dot color. |
data-button-color |
Hex or CSS color | #111 |
Floating launcher background. Ignored with data-trigger. |
data-button-text-color |
Hex or CSS color | #fff |
Floating launcher text. |
data-trigger |
CSS selector | (none) | Bind to your own element instead of rendering a floating launcher. |
data-project |
Slug | derived from data-base |
Key the per-visitor "seen" state stores under. Override only if one origin serves more than one changelog. |
See the full guide for the long-form version of each.
The widget does three small things, all against your *.jamdesk.app origin:
- Fetches
<data-base>/changelog.json— a tiny file Jamdesk builds from your changelog's newest entry. It carries the latest entry's id and a count. If there's no changelog, the floating launcher stays hidden. - Tracks unread per visitor. The newest entry's id is compared against a value in the browser's
localStorage(jd_seen_<project>). They differ → a dot shows. Opening the modal marks the entry seen and clears it. No account, no tracking; clearing site data resets it. - Opens the modal on click. A native
<dialog>renders your page in an iframe with?embed=1, which strips the site chrome and keeps the theme and typography. ESC and a backdrop click close it.
The changelog feed is opt-in: a page only feeds the widget when its frontmatter sets rss: true. A page that just demonstrates the <Update> component won't light up the dot.
Runnable HTML is in examples/. Open any file in a browser after editing acme to your own subdomain.
<!-- Bound to your own nav link, no floating button -->
<script
src="https://acme.jamdesk.app/_jd/widget.js"
data-base="https://acme.jamdesk.app"
data-trigger="#whats-new"
async
></script><!-- Bottom-left, green dot, custom label -->
<script
src="https://acme.jamdesk.app/_jd/widget.js"
data-base="https://acme.jamdesk.app"
data-position="bottom-left"
data-label="Release notes"
data-unread-color="#22c55e"
async
></script>ES2022+: Chrome / Edge / Firefox 94+, Safari 15.4+. The modal uses the native <dialog> element and showModal() for top-layer stacking and focus containment. There are no polyfills and no dependencies.
If your site sends a strict CSP, allow your *.jamdesk.app origin in three directives (script-src for the script, frame-src for the modal iframe, connect-src for the changelog fetch). Details and the exact header are in the CSP section of the guide. Self-hosting moves the script-src requirement to your own origin.
Don't embed the widget if your docs site is password-protected. The unlock screen is meant to be entered first-party on your *.jamdesk.app site, not inside a third-party iframe. Keep the widget for public changelogs.
Releases follow semantic versioning. The hosted copy (Option 1) always tracks the latest release. Pin a tag with jsDelivr (Option 2) when you want a fixed version. See CHANGELOG.md and the releases page.
- Embed Your Changelog — the full guide
<Update>component — write the entries the widget reads- Jamdesk dashboard — generate your snippet under Settings
- Jamdesk docs
MIT © Jamdesk
