Skip to content

Instantly share code, notes, and snippets.



Last active Feb 3, 2020
What would you like to do?
Using Hypothesis in a JavaScript SPA with client-side routing

This is a sample which demonstrates how to use Hypothesis <= v0.21.0 in a JavaScript Single Page Application which does client-side routing.

The current version of Hypothesis at the time of writing does not automatically update the loaded annotations when the page URL changes. This sample takes the heavy-handed approach of completely removing and reloading Hypothesis when the URL changes. In future we'll look to build this into Hypothesis automatically in a much more performant way.

Running the demo

  1. Download files from this gist and extract into a directory
  2. Run python -m SimpleHTTPServer 8000
  3. Navigate to http://locahost:8000/demo.html
  4. Switch chapters using Chapter links in left navbar
.container {
display: flex;
flex-direction: row;
margin: auto;
max-width: 800px;
.navbar {
max-width: 200px;
padding: 20px;
background-color: #ddd;
.content {
width: 500px;
border: 1px solid #ddd;
padding: 10px;
<meta charset="UTF-8">
<link rel="stylesheet" href="demo.css">
<script src=""></script>
<div class="container">
<nav class="navbar">
<a href="/demo.html">Home</a>
<a href="/chapters/1">Chapter 1</a>
<a href="/chapters/2">Chapter 2</a>
<a href="/chapters/3">Chapter 3</a>
<main class="content js-content">
<script src="demo.js"></script>
var CONTENT = {
'1': 'This is the content for the first chapter',
'2': 'Content for the second chapter',
'3': 'Content for the third chapter',
function reloadHypothesis() {
var H_SERVER = '';
// Remove existing Hypothesis instance (if any)
var links = [].slice.apply(document.querySelectorAll('link'));
links.forEach(function (linkEl) {
if (linkEl.type === 'application/annotator+html' ||
linkEl.href.startsWith(H_SERVER)) {
var scripts = [].slice.apply(document.querySelectorAll('script'));
scripts.forEach(function (scriptEl) {
if (scriptEl.src.startsWith(H_SERVER)) {
if (window.annotator) {
// Remove event listeners for existing Hypothesis
// instance. This works around a bug in Hypothesis <= 0.21.0
// where window.annotator.destroy() fails to do this itself.
var jq = require('jquery');
var events = ['beforeAnnotationCreated',
events.forEach(function (event) {
// Remove the Hypothesis UI from the page
// Install Hypothesis for current URL
var embedScriptEl = document.createElement('script');
embedScriptEl.src = H_SERVER + '/embed.js';
var contentEl = document.querySelector('.js-content');
page('/demo.html', function () {
contentEl.innerHTML = 'Click the chapter links on the left';
page('/chapters/:id', function (context) {
contentEl.innerHTML = CONTENT[];
document.addEventListener('DOMContentLoaded', function () {

This comment has been minimized.

Copy link

@tingletech tingletech commented Oct 14, 2019

@robertknight is this still the recommended approach to deal with the issue?


This comment has been minimized.

Copy link
Owner Author

@robertknight robertknight commented Oct 15, 2019

The part from // Remove existing Hypothesis instance (if any) up until // Install Hypothesis for current URL is obsolete and should be replaced with the method at Otherwise yes, this approach is still the best available.


This comment has been minimized.

Copy link

@matt-e-king matt-e-king commented Feb 3, 2020

@robertknight when is called, is this also closing the websocket that was opened by that specific instance of the client?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment