ability to update location.hash programmatically?

UPDATE: I just discovered that it’s already possible to update the URL hash by doing this:

window.parent.postMessage({ type: 'navigate', href: '#foo' }, 'https://observablehq.com')

@mbostock Is this in the docs somewhere or did I stumble upon internal logic that I’m not supposed to be using?


I know that the value of window.location.hash is passed down into the cell context, but is it possible to go in the other direction and modify the location hash from cell code? My attempts so far have been unsuccessful, and I assume that this is due to the limitations imposed by executing code within an iframe. Is it possible to work around this limitation? (My guess is that it isn’t possible without help from the Observable runtime.)

My ultimate goal is to allow the user to share links to the notebook that initialize a specific state. Automatically updating the hash with state information would be a convenient way to achieve this goal, and it would have the additional benefit of preserving the user’s state across reloads.

Edit: Just noticed the allow-top-navigation-by-user-activation sandbox policy on the Observable iframe… that explains why I can’t modify location.hash even though links in cells can alter the hash when clicked. Still, I wonder if there’s a way for the Observable standard library to enable a reactive mapping between state and location.hash. Maybe something could be set up using window.postMessage?

Another solution would be to change the sandbox policy to allow-top-navigation. However, I understand if the Observable team thinks that would be too risky. Also, I think it would still require referencing window.parent, and I feel like this would make the iframe context of Observable code too explicit. Ideally the cell code shouldn’t need to know anything about iframes and window hierarchies.

5 Likes

After going through all this trouble to figure out how to reactively change the hash, I decided it’s probably not a good idea after all, as each change will add another entry to the browser history and essentially break the Back button. There are ways of updating the hash without modifying the browser history (using history.replaceState or location.replace), but those would require direct access to the parent window, and anyway it’s probably better to just display a shareable link in a notebook cell instead of messing around with the URL.

(Unfortunately it seems like navigator.clipboard.writeText() can’t be used to copy a link automatically, as the iframe context results in a Document not focused error.)

2 Likes

Yup, I recommend that for now. But perhaps in the future I could see us supporting something like replaceState for setting the query string or hash. Thanks for the feedback!

1 Like