Class SScrollPane

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.orderedlayout.Scroller
com.vaadin.swingbridge.surrogates.SScrollPane
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.BlurNotifier<com.vaadin.flow.component.orderedlayout.Scroller>, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.Focusable<com.vaadin.flow.component.orderedlayout.Scroller>, com.vaadin.flow.component.FocusNotifier<com.vaadin.flow.component.orderedlayout.Scroller>, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasTheme, com.vaadin.flow.component.shared.HasThemeVariant<com.vaadin.flow.component.orderedlayout.ScrollerVariant>, ComponentMixin, ContainerMixin, Serializable

public class SScrollPane extends com.vaadin.flow.component.orderedlayout.Scroller implements ContainerMixin
Surrogate for ScrollPane — AWT's scrolling container, not JScrollPane. Extends Vaadin Scroller directly (is-a) and picks up the AWT Container API from ContainerMixin. Rationale: SD_sscrollpane / D_awt_scrollpane.
SScrollPane pane = new SScrollPane(java.awt.ScrollPane.SCROLLBARS_AS_NEEDED);
pane.setContent(tallStack);
pane.scrollTo(0, 200);          // pushed to the browser; nothing reads back

Why Scroller, and why not SJScrollPane

Scroller's single content slot is AWT's single-child rule, and its ScrollDirection covers the scrollbar display policy at the fidelity D_scrollbar_policy_mapping already accepted. Reusing SJScrollPane was rejected for SD_sbutton/SD_slabel's reason: it implements JComponentMixin and so drags in border CSS, client properties, the opaque flag, tooltips and the L&F tail — none of which java.awt.ScrollPane has, being a Container rather than a JComponent.

This class holds no state, deliberately

The scroll direction lives on the Scroller (Vaadin-first, no shadow) and the JDK-shaped display-policy int lives on the emulator, exactly as D_scrollbar_policy_mapping puts the Swing policy ints on JScrollPane and not on SJScrollPane. The scroll offset would have been this class's one legitimate holding — a browser fact, the FocusTracker / SD_focus_tracker shape — but with the browser→server channel descoped it is no longer a browser fact, merely the last value the emulator pushed, and the emulator's two ScrollPaneAdjustables already own that. Storing it here as well would be the shadow-cache anti-pattern R_vaadin_first exists to forbid.

Scrolling is server→browser only

scrollTo(int, int) pushes; nothing reads back. There is no scroll DOM listener on this element, so a user's wheel or drag is invisible to the server: getScrollPosition() on the emulator answers what was last pushed, and no AdjustmentListener fires for a gesture. Deliberate per SD_sscrollpane, which also records the probe finding that scroll neither bubbles nor composes (so a delegated UI-wide listener is not an option).

Auto-scroll guard

setContent(Component) forces Scroller.ScrollDirection.NONE for content that owns its own overflow layer, exactly as SJScrollPane does. The two copies are deliberate duplication rather than a shared util: lifting ~15 lines would mean touching a Swing-lane class for an AWT-lane slice. If you change one, change the other — SJScrollPane.setContent(Component).
See Also:
  • Constructor Details

    • SScrollPane

      public SScrollPane(int scrollbarDisplayPolicy)
      Parameters:
      scrollbarDisplayPolicy - one of java.awt.ScrollPane's SCROLLBARS_* constants
      Throws:
      IllegalArgumentException - on any other value, with AWT's own message. Validating here rather than in the emulator is D_awt_label's trick: the throw comes out of the emulator's super(...) call, so no half-built ScrollPane is left behind.
  • Method Details

    • scrollTo

      public void scrollTo(int x, int y)
      Scrolls the peer element to (x, y), in pixels.

      Scroller exposes only scrollToTop() / scrollToBottom(), so this goes through executeJs — the SD_caret_selection shape (server→browser only, server value is the source of truth). Verified 2026-08-25 that vaadin-scroller's shadow root is a bare <slot> with overflow: auto on the host, so this.scrollTop addresses the real scrolling box and needs no shadowRoot selector.

      Fire-and-forget: an out-of-range value is clamped by the browser on arrival (verified synchronous), so the rendered result is always legal even when the caller's number is optimistic. Nothing reports the clamped value back.

    • setContent

      public void setContent(com.vaadin.flow.component.Component content)
      Set the scrolled content, applying the auto-scroll guard.

      Delegates to Scroller.setContent(Component), then if the content is an instance of any known auto-scrolling Vaadin component type, forces this Scroller's direction to Scroller.ScrollDirection.NONE and stretches the content to fill the viewport. Prevents the stacked-scrollbar pathology when a Grid / TextArea / Scroller is wrapped.

      null content clears the slot without applying the guard.

      Note this does not re-push the scroll offset, though replacing content resets the browser's scrollTop to 0: this class does not know the offset. The emulator's addImpl re-pushes from its adjustables instead.

      Overrides:
      setContent in class com.vaadin.flow.component.orderedlayout.Scroller
    • getLayout

      public LayoutManager getLayout()
      A ScrollPane's layout is nailed to null forever, so this always answers null — matching the JDK field that setLayout(LayoutManager) refuses to write.

      Nothing can ever reach LayoutStore, so the ContainerMixin default would answer null too; stated directly so the contract does not depend on setLayout's throw holding.

      Specified by:
      getLayout in interface ContainerMixin
    • setLayout

      public void setLayout(LayoutManager mgr)
      Refuses to install a layout manager, as java.awt.ScrollPane does.

      The ContainerMixin default would store into LayoutStore and write layout CSS — right for a panel, wrong here — so it is overridden away. A stage-3 pure-surrogate user reaching for setLayout deserves the same answer as a stage-2 one.

      Specified by:
      setLayout in interface ContainerMixin
      Throws:
      AWTError - always, with AWT's own message, even for null