Adding new Turbo Frames to a page in response to user interaction

I have wanted to build an app for myself that publishes a collection of notes and borrows some UI ideas from Andy Matuschak’s notes website.

At first glance it looks like Turbo Frames could be a really good fit, but after a bit of investigating, I’m not so sure. Posting this here in case anyone can point out a way of achieving something like this in a Turbo Frames way.

Background:

When you visit https://notes.andymatuschak.org/ in a desktop browser it provides a lovely means of navigating a collection of linked notes. Clicking a link in one note opens the next note in a new column, without replacing the note you are already viewing. This is a lot like the Column view in macOS Finder. You can create an arbitrary number of columns, each with a separate note by navigating through the links. Here is a screenshot:

Achieving this using TurboFrames:

When I saw Turbo Frames, I thought this could be a good fit. Each column could be a new Turbo Frame and lazy-load the next note as the user navigates via the links embedded in each note.

Too keep things simple, I would like to find a solution that can be hosted as a static site with each note as a separate HTML file:

/note-a.html
/note-b.html
/note-c.html
…

Here is my first thought about how this would be done using Turbo Frames:

  • The user could start by navigating to any note. For example /note-a.html. The page would start with a single Turbo Frame (Frame 1) wrapping the main content of note-a.html.
  • When the user clicks a link in note-a to another note (for example note-b), a new Turbo Frame is added to the DOM using javascript (Frame 2) and lazy-loads the content of note-b.

This is where Turbo Frames starts to look less useful for this application… Two problems:

  1. Getting javascript to add and remove Turbo Frames to the DOM feels like it is working against the simplicity of Turbo Frames and the ethos of Hotwire in general. The JS required would be more than just a “sprinkle” (to use DHH’s words :slight_smile:).

  2. Turbo Frames that are lazy-loaded need to matching id of the Frame they are replacing. In this case Frame 2 would need to have an id that matches the id of the Turbo Frame wrapping the content in note-b. This means that we would need to know the id of the Turbo Frame on note-b.html before adding Frame 2 to the DOM of note-a.html.

Neither of these make Turbo Frames impossible to use for this use-case. But these challenges feel like Turbo Frames might not be a good fit. The attraction for me is the simplicity, so I’d like to avoid working against the grain of Turbo/Hotwire.

A solution to problem 1 that avoids manipulating the DOM too much might be to include a bunch of hidden Turbo Frames that are just revealed when needed.

Problem 2 could be solved by using a more dynamic back end that stores the note content in a database and wraps the content with a Turbo Frame with an ID that matches the Frame on the client (for example frame-2). I would love to avoid building a dynamic back end though!

Very interested to know if anyone has any thoughts or can suggest an approach that is more in line with the Hotwire / Turbo framework.