Facundo Espinosa

March 20, 2024

Turbo Frames autoscroll feature

Turbo tries to solve many general use cases by default with the idea of reduce developers work. One of those features is the autoscrolling for turbo frames.

How autoscroll works? Let's ready the documentation:

autoscroll is a boolean attribute that controls whether or not to scroll a <turbo-frame> element (and its descendant <turbo-frame> elements) into view when after loading. Control the scroll’s vertical alignment by setting the data-autoscroll-block attribute to a valid Element.scrollIntoView({ block: “…” }) value: one of "end", "start", "center", or "nearest". When data-autoscroll-block is absent, the default value is "end". Control the scroll’s behavior by setting the data-autoscroll-behavior attribute to a valid Element.scrollIntoView({ behavior: “…” }) value: one of "auto", or "smooth". When data-autoscroll-behavior is absent, the default value is "auto".

ref: https://turbo.hotwired.dev/reference/frames#html-attributes

So, just adding `autoscroll` property to a turbo-frame it will autoscroll the page to that point on when it loads and we can control where to leave the frame (start, center, end) on the screen and the behavior of the scroll (auto, smooth). That's a great built-in feature.

As it specifies, it uses Element.scrollIntoView({ block: “…” }) behind the hood. How is the element obtained?

We can check the scrollFrameIntoView implementation:

// src/core/frames/frame_renderer.js

scrollFrameIntoView() {
    if (this.currentElement.autoscroll || this.newElement.autoscroll) {
      const element = this.currentElement.firstElementChild
      const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end")
      const behavior = readScrollBehavior(this.currentElement.getAttribute("data-autoscroll-behavior"), "auto")

      if (element) {
        element.scrollIntoView({ block, behavior })
        return true
      }
    }
    return false
  }


We can see that the element is obtained taking the `firstElementChild` of the `currentElement` which is the turbo-frame. Then it takes the block and behavior values and if the element is present then it will take the `element` and `scrollIntoView` with those properties.

But in some cases this will not just work. Let's see the `scrollIntoView` specification:

CleanShot 2024-03-19 at 20.15.28.png

ref: https://drafts.csswg.org/cssom-view/#dom-element-scrollintoview

We see this interesting part mentioning the box. If no box associated, no scroll will happen. What the box exactly mean?

CleanShot 2024-03-19 at 20.18.24.png

ref: https://drafts.csswg.org/css-display-4/#intro

Here we found it, the box is determined by the element's display property, but some values of this properties cause to not generate any boxes, as described, values `none` and `contents` will do this. 

Conclusion:


If we take any element with the property `display` with the value `none` or `contents` and try to `scrollIntoView` it won't work (autoscroll feature won't work), and it will not show any reason why.