14.4 Scroller not working inside HorizontalLayout

I have an UI with a header, a footer and a content view in between.
The content view is a HorizontalLayout with a fixed with menu on the left and the actual content.
The content is wrapped in a Scroller to get scroll bars if the content height is to big.
Simplified something like:
VerticalLayout(
HorizontalLayout(header),
HorizontalLayout(menu, Scroller(content)),
HorizontalLayout(footer)
)

This does not work. If the content gets to tall, the footer gets pushed down outside of the browser window.

Without a HorizontalLayout (Scroller only as content) all is ok.
VerticalLayout(
HorizontalLayout(header),
Scroller(content),
HorizontalLayout(footer)
)

Is this a bug of Scroller or can I fix this in my sources?
How can I get a working Scroller in the middle of my UI?
Any hints?

Thanx

Alex

What if you wrap the middle HorizontalLayout (the one with the menu and the content) in the Scroller instead?

Addenum: The situation sounds to me like the HorizontalLayout is not limited in size; the Scroller is the component that defines the height (and the Scroller gets its height from the content), so there’s no need to get a scrollbar. If the Scroller’s height got limited by something, then it would need to show a scrollbar.

Wrapping the HorizontalLayout in Sroller is no option because of the design of the UI.
The layout should be like

Header (HorizontalLayout)
Menu (VerticalLayout or FlexLayout), ItemList (Grid), ItemDetails (Scroller)
Footer (HorizontalLayout)

The middle line should get all remaining space.
I have simplified this in a test case like following pseudo code:

mid = Scroller(
	Div()
)
vert = new VerticalLayout()
vert.add(HorizontalLayout(...))
vert.addAndExpand(HorizontalLayout(mid))   // vert.addAndExpand(mid)is working fine 
vert.add(HorizontalLayout(...))
vert.setSizeFull();

If the height of the Div expands the remaining space, a scroll bar around the Div should appear but this does not happen.

The Scroller’s height seems not to be limited, if wrapped in a HorizontalLayout.
The Scrollers height gets limited, if there is no HorizontalLayout around it.

How can I limit the height for the Scroller in the HorizontalLayout?
I guess I have to limit the height of the HorizontalLayout but how? It’s height depends on the height of the browser window.

I can’t be sure without having the code, but I’m guessing your problem is that at some point in your hierarchy, you have an undefined height. Possibly the class which contains your vert VerticalLayout? It should be pretty easy to determine this in browser developer tools. If you have an undefined height parent there, it means that the contents will be determining the height and thus, the Scroller won’t ever need a scrollbar of its own. Otherwise, your pseudocode looks more or less correct.

This is the complete Source code of my test case:

package de.isys.testscroller;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.Scroller;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;

/**
 * The main view contains a button and a click listener.
 */
@Route("")
@PWA(name = "Project Base for Vaadin", shortName = "Project Base", enableInstallPrompt = false)
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field")
public class MainView extends VerticalLayout {

    public MainView() {

        final Div okContent = createScrollerContent("Resize ok");
        final Div errorContent = createScrollerContent("Error resizing inside HorizontalLayout");
        final Scroller ok = createScroller(okContent);
        final Scroller error = createScroller(errorContent);

        HorizontalLayout header = createHori("Header");
        header.add(
            createButton(okContent, "shrink ok", "100px"),
            createButton(okContent, "heighten ok", "1000px"),
            createButton(errorContent, "shrink error", "100px"),
            createButton(errorContent, "heighten error", "1000px")
        );

        HorizontalLayout footer = createHori("Footer");

        HorizontalLayout horiErr = new HorizontalLayout(error);
        horiErr.getStyle().set("background-color", "aliceblue");
        horiErr.setWidthFull();
        
        add(header);
        // addAndExpand(ok);    // This works
        addAndExpand(horiErr);  // This not
        add(footer);
        setSizeFull();
    }
    private Button createButton(final Component comp, final String text, final String height) {
        return new Button(text, e -> ((HasSize)comp).setHeight(height));
    }
    private Div createScrollerContent(final String text) {
        Div resizeable = new Div();
        resizeable.setText(text);
        resizeable.getStyle().set("background-color", "red");
        resizeable.setWidthFull();
        resizeable.setHeight("100px");
        return resizeable;
    }
    private Scroller createScroller(final Div resizeable) {
        Scroller scroller = new Scroller(resizeable);
        scroller.setWidthFull();
        return scroller;
    }
    private HorizontalLayout createHori(String text) {
        HorizontalLayout hori = new HorizontalLayout(new Span(text));
        hori.setWidthFull();
        hori.getStyle().set("background-color", "aqua");
        return hori;
    }
}

The parent of the Scroller is the HorizontalLayout, the parent of the HorizontalLayout is the VerticalLayout which is the main layout.
Both, the Scoller and the HorizontalLayout grow if the Div grows.

Your horiErr HorizontalLayout has an undefined height, which means that its height will be determined by its contents. Set any fixed size to horiErr so the Scroller’s element knows that it’s not the one that determines the height of its parent.

But I do not know which height to set for horiErr because its height depends on the height of the browser window (minus header, minus footer).
How to advice a HorizontalLayout to use only the remaining space as height?

Give it any fixed size, like 100px, or something that’s suitable for displaying the content if there is no surplus free space. Using addAndExpand sets the flex-grow property to 1. This means that if there is any free space available in the container after adding the “natural” sized items, the HorizontalLayout item will expand to take up any free space available.

If you have multiple items with the flex-grow CSS property set, then any free space will be divided among these items according to the flex-grow ratio, so for example 1:1:1 if three items were added with addAndExpand. You can also manually give an item a larger portion of the free space by setting the flex-grow manually with e.g. layout.setFlexGrow(2.5, someComponent);.

Thanks Olli, this was the hint in the right direction.
Instead of a fixed size I had to set minHeight for horiErr.