Skip to content

Commit 46e8c23

Browse files
authored
feat: Add varargs-based scrollIntoView API (#22591)
Allows doing ``` component.scrollIntoView(ScrollIntoViewOption.Behavior.SMOOTH, ScrollIntoViewOption.Block.END, ScrollIntoViewOption.Inline.CENTER); ``` without creating an intermediate options object. Consistent with the `focus(...)` API
1 parent fb2581e commit 46e8c23

File tree

5 files changed

+331
-5
lines changed

5 files changed

+331
-5
lines changed

flow-server/src/main/java/com/vaadin/flow/component/Component.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,18 +796,45 @@ protected Locale getLocale() {
796796
/**
797797
* Scrolls the current component into the visible area of the browser
798798
* window.
799+
* <p>
800+
* This method can be called with no arguments for default browser behavior,
801+
* or with one or more {@link ScrollIntoViewOption} values to control
802+
* scrolling behavior:
803+
* <ul>
804+
* <li>{@link ScrollIntoViewOption.Behavior} - controls whether scrolling is
805+
* instant or smooth</li>
806+
* <li>{@link ScrollIntoViewOption.Block} - controls vertical alignment of
807+
* the element</li>
808+
* <li>{@link ScrollIntoViewOption.Inline} - controls horizontal alignment
809+
* of the element</li>
810+
* </ul>
811+
* <p>
812+
* Examples:
813+
*
814+
* <pre>
815+
* component.scrollIntoView(ScrollIntoViewOption.Behavior.SMOOTH);
816+
* component.scrollIntoView(ScrollIntoViewOption.Block.END);
817+
* component.scrollIntoView(ScrollIntoViewOption.Behavior.SMOOTH,
818+
* ScrollIntoViewOption.Block.END,
819+
* ScrollIntoViewOption.Inline.CENTER);
820+
* </pre>
821+
*
822+
* @param options
823+
* zero or more scroll options
799824
*/
800-
public void scrollIntoView() {
801-
scrollIntoView(null);
825+
public void scrollIntoView(ScrollIntoViewOption... options) {
826+
getElement().scrollIntoView(options);
802827
}
803828

804829
/**
805830
* Scrolls the current component into the visible area of the browser
806831
* window.
807832
*
833+
* @deprecated Use {@link #scrollIntoView(ScrollIntoViewOption...)} instead
808834
* @param scrollOptions
809835
* options to define the scrolling behavior
810836
*/
837+
@Deprecated(since = "25.0", forRemoval = true)
811838
public void scrollIntoView(ScrollOptions scrollOptions) {
812839
getElement().scrollIntoView(scrollOptions);
813840
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright 2000-2025 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.component;
17+
18+
import java.io.Serializable;
19+
20+
import tools.jackson.databind.node.ObjectNode;
21+
22+
import com.vaadin.flow.internal.JacksonUtils;
23+
24+
/**
25+
* Marker interface for scrollIntoView options.
26+
* <p>
27+
* Implementations of this interface can be passed to
28+
* {@link com.vaadin.flow.dom.Element#scrollIntoView(ScrollIntoViewOption...)}
29+
* and {@link Component#scrollIntoView(ScrollIntoViewOption...)}.
30+
* <p>
31+
* See <a href=
32+
* "https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView">Element.scrollIntoView()</a>
33+
* for more information.
34+
*/
35+
public interface ScrollIntoViewOption extends Serializable {
36+
37+
/**
38+
* Builds an ObjectNode containing the scrollIntoView options for use with
39+
* the browser's scrollIntoView() method.
40+
* <p>
41+
* This method extracts Behavior, Block, and Inline options from the varargs
42+
* and builds a JSON object compatible with the browser's
43+
* Element.scrollIntoView() API. Returns null if no options are provided.
44+
*
45+
* @param options
46+
* zero or more scrollIntoView options
47+
* @return an ObjectNode with the scrollIntoView options, or null if no
48+
* options are provided
49+
*/
50+
static ObjectNode buildOptions(ScrollIntoViewOption... options) {
51+
// Extract options from varargs
52+
Behavior behavior = null;
53+
Block block = null;
54+
Inline inline = null;
55+
56+
for (ScrollIntoViewOption option : options) {
57+
if (option instanceof Behavior) {
58+
behavior = (Behavior) option;
59+
} else if (option instanceof Block) {
60+
block = (Block) option;
61+
} else if (option instanceof Inline) {
62+
inline = (Inline) option;
63+
}
64+
}
65+
66+
// Return null if no options provided
67+
if (behavior == null && block == null && inline == null) {
68+
return null;
69+
}
70+
71+
// Build options object
72+
ObjectNode json = JacksonUtils.createObjectNode();
73+
74+
if (behavior != null) {
75+
json.put("behavior", behavior.getValue());
76+
}
77+
78+
if (block != null) {
79+
json.put("block", block.getValue());
80+
}
81+
82+
if (inline != null) {
83+
json.put("inline", inline.getValue());
84+
}
85+
86+
return json;
87+
}
88+
89+
/**
90+
* Scroll behavior option for scrollIntoView operations.
91+
* <p>
92+
* Controls whether scrolling is instant or smooth.
93+
*/
94+
enum Behavior implements ScrollIntoViewOption {
95+
/**
96+
* Scrolling happens instantly in a single jump.
97+
*/
98+
AUTO,
99+
100+
/**
101+
* Scrolling is animated smoothly.
102+
*/
103+
SMOOTH;
104+
105+
/**
106+
* Gets the lowercase string value for this behavior.
107+
*
108+
* @return the lowercase string representation
109+
*/
110+
public String getValue() {
111+
return name().toLowerCase(java.util.Locale.ENGLISH);
112+
}
113+
}
114+
115+
/**
116+
* Vertical alignment option for scrollIntoView operations.
117+
* <p>
118+
* Defines the vertical alignment of the element within the visible area.
119+
*/
120+
class Block implements ScrollIntoViewOption {
121+
/**
122+
* Aligns the element to the top of the scrolling area.
123+
*/
124+
public static final Block START = new Block("start");
125+
126+
/**
127+
* Aligns the element to the center of the scrolling area.
128+
*/
129+
public static final Block CENTER = new Block("center");
130+
131+
/**
132+
* Aligns the element to the bottom of the scrolling area.
133+
*/
134+
public static final Block END = new Block("end");
135+
136+
/**
137+
* Aligns the element to the nearest edge of the scrolling area.
138+
*/
139+
public static final Block NEAREST = new Block("nearest");
140+
141+
private final String value;
142+
143+
private Block(String value) {
144+
this.value = value;
145+
}
146+
147+
public String getValue() {
148+
return value;
149+
}
150+
}
151+
152+
/**
153+
* Horizontal alignment option for scrollIntoView operations.
154+
* <p>
155+
* Defines the horizontal alignment of the element within the visible area.
156+
*/
157+
class Inline implements ScrollIntoViewOption {
158+
/**
159+
* Aligns the element to the left of the scrolling area.
160+
*/
161+
public static final Inline START = new Inline("start");
162+
163+
/**
164+
* Aligns the element to the center of the scrolling area.
165+
*/
166+
public static final Inline CENTER = new Inline("center");
167+
168+
/**
169+
* Aligns the element to the right of the scrolling area.
170+
*/
171+
public static final Inline END = new Inline("end");
172+
173+
/**
174+
* Aligns the element to the nearest edge of the scrolling area.
175+
*/
176+
public static final Inline NEAREST = new Inline("nearest");
177+
178+
private final String value;
179+
180+
private Inline(String value) {
181+
this.value = value;
182+
}
183+
184+
public String getValue() {
185+
return value;
186+
}
187+
}
188+
}

flow-server/src/main/java/com/vaadin/flow/component/ScrollOptions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@
2626
* Options for scrollIntoView.
2727
* <p>
2828
* See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
29+
*
30+
* @deprecated Use
31+
* {@link com.vaadin.flow.dom.Element#scrollIntoView(ScrollIntoViewOption...)}
32+
* with {@link ScrollIntoViewOption.Behavior},
33+
* {@link ScrollIntoViewOption.Block}, and
34+
* {@link ScrollIntoViewOption.Inline} options instead
2935
**/
36+
@Deprecated(since = "25.0", forRemoval = true)
3037
public class ScrollOptions implements Serializable {
3138
/**
3239
* Scroll behavior for scrollIntoView.

flow-server/src/main/java/com/vaadin/flow/dom/Element.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434
import tools.jackson.databind.node.BaseJsonNode;
3535
import tools.jackson.databind.node.BooleanNode;
3636
import tools.jackson.databind.node.NullNode;
37+
import tools.jackson.databind.node.ObjectNode;
3738

3839
import com.vaadin.flow.component.Component;
3940
import com.vaadin.flow.component.ComponentUtil;
41+
import com.vaadin.flow.component.ScrollIntoViewOption;
4042
import com.vaadin.flow.component.ScrollOptions;
4143
import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
4244
import com.vaadin.flow.component.internal.UIInternals.JavaScriptInvocation;
@@ -1836,26 +1838,65 @@ private void informChildrenOfStateChange(boolean enabled, Element element) {
18361838

18371839
/**
18381840
* Executes the similarly named DOM method on the client side.
1841+
* <p>
1842+
* This method can be called with no arguments for default browser behavior,
1843+
* or with one or more {@link ScrollIntoViewOption} values to control
1844+
* scrolling behavior:
1845+
* <ul>
1846+
* <li>{@link ScrollIntoViewOption.Behavior} - controls whether scrolling is
1847+
* instant or smooth</li>
1848+
* <li>{@link ScrollIntoViewOption.Block} - controls vertical alignment of
1849+
* the element</li>
1850+
* <li>{@link ScrollIntoViewOption.Inline} - controls horizontal alignment
1851+
* of the element</li>
1852+
* </ul>
1853+
* <p>
1854+
* Examples:
1855+
*
1856+
* <pre>
1857+
* element.scrollIntoView(); // Default behavior
1858+
* element.scrollIntoView(ScrollIntoViewOption.Behavior.SMOOTH); // Smooth
1859+
* // scrolling
1860+
* element.scrollIntoView(ScrollIntoViewOption.Block.END); // Scroll to
1861+
* // bottom
1862+
* element.scrollIntoView(ScrollIntoViewOption.Behavior.SMOOTH,
1863+
* ScrollIntoViewOption.Block.END,
1864+
* ScrollIntoViewOption.Inline.CENTER); // All options
1865+
* </pre>
18391866
*
1867+
* @param options
1868+
* zero or more scroll options
1869+
* @return the element
18401870
* @see <a href=
18411871
* "https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView">Mozilla
18421872
* docs</a>
1843-
* @return the element
18441873
*/
1845-
public Element scrollIntoView() {
1846-
return scrollIntoView(null);
1874+
public Element scrollIntoView(ScrollIntoViewOption... options) {
1875+
ObjectNode json = ScrollIntoViewOption.buildOptions(options);
1876+
1877+
// Use setTimeout to work on newly created elements
1878+
if (json == null) {
1879+
executeJs("setTimeout(function(){$0.scrollIntoView()},0)", this);
1880+
} else {
1881+
executeJs("setTimeout(function(){$0.scrollIntoView($1)},0)", this,
1882+
json);
1883+
}
1884+
1885+
return getSelf();
18471886
}
18481887

18491888
/**
18501889
* Executes the similarly named DOM method on the client side.
18511890
*
1891+
* @deprecated Use {@link #scrollIntoView(ScrollIntoViewOption...)} instead
18521892
* @see <a href=
18531893
* "https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView">Mozilla
18541894
* docs</a>
18551895
* @param scrollOptions
18561896
* the scroll options to pass to the method
18571897
* @return the element
18581898
*/
1899+
@Deprecated(since = "25.0", forRemoval = true)
18591900
public Element scrollIntoView(ScrollOptions scrollOptions) {
18601901
// for an unknown reason, needs to be called deferred to work on a newly
18611902
// created element

0 commit comments

Comments
 (0)