Call element.scrollIntoView({ behavior: 'smooth', block: 'start' }) to bring an element into view. block decides where it lands vertically: start, center, end or nearest. If a sticky header covers the target, give the target scroll-margin-top equal to the header height in CSS instead of calculating offsets in JavaScript.
| Option | Values | Default |
|---|---|---|
| behavior | "smooth", "instant", "auto" (follows CSS scroll-behavior) | "auto" |
| block (vertical) | "start", "center", "end", "nearest" | "start" |
| inline (horizontal) | "start", "center", "end", "nearest" | "nearest" |
| true / false instead of options | true = block start, false = block end (inline nearest) | true |
Updated
There are three ways to move the page to an element: scrollIntoView on the element, scrollTo with a pixel position, and a plain link to an id. The playground shows what each block value does and how scroll-margin-top keeps a heading clear of a fixed bar, then the examples cover the code you need for menus, form errors and chat style lists.
Looks the element up by id and brings its top edge to the top of the view.
document.getElementById("pricing")
?.scrollIntoView({ behavior: "smooth", block: "start" });One rule fixes the overlap for scripted scrolls and for links that end in #id. The media query skips the animation for people who prefer reduced motion.
:root { --header-h: 72px; }
[id] { scroll-margin-top: calc(var(--header-h) + 8px); }
@media (prefers-reduced-motion: no-preference) {
html { scroll-behavior: smooth; }
}center keeps the field and its label in the middle of the screen; focus moves keyboard users there too.
form.addEventListener("submit", (e) => {
const bad = form.querySelector(":invalid");
if (!bad) return;
e.preventDefault();
bad.scrollIntoView({ behavior: "smooth", block: "center" });
bad.focus({ preventScroll: true });
});Uses the item's position inside the panel, so the page around it does not move.
function scrollPanelTo(panel, item, offset = 0) {
const top = item.getBoundingClientRect().top
- panel.getBoundingClientRect().top
+ panel.scrollTop - offset;
panel.scrollTo({ top, behavior: "smooth" });
}The ref points at the DOM node once it has rendered, so the call happens in a click handler or an effect.
function Faq() {
const answerRef = useRef(null);
return (
<>
<button onClick={() => answerRef.current?.scrollIntoView({ behavior: "smooth" })}>
Jump to the answer
</button>
<section ref={answerRef}>...</section>
</>
);
}
start suits jumps to a section or heading, because the reader begins at the top of it. center works well for drawing attention to a single field, such as the first invalid input on a form. end fits a chat or log where the newest item should sit at the bottom.
nearest is the polite option: it moves the least distance needed and leaves visible items alone, which is what you want when an arrow key moves the highlight through a list.
An ordinary link such as <a href="#pricing"> already scrolls to the element with id pricing, updates the address bar and works with the back button. Add scroll-behavior: smooth to the html element and scroll-margin-top to the targets, and many table of contents menus need no script at all.
Reach for JavaScript when the scroll follows something that is not a click on a link: a form failing validation, a new message arriving or a search result being selected.
Add scroll-margin-top to the target, for example h2 { scroll-margin-top: 80px }. The CSS scroll snap specification asks browsers to honour that margin for scrollIntoView and for links to #ids, even with no snapping in use.
Pass behavior: 'smooth' to scrollIntoView or scrollTo, or set scroll-behavior: smooth on the html element so every programmatic scroll and in-page link animates. scroll-behavior has no effect on scrolling done by the user with a wheel or touch.
scrollIntoView works from an element and figures out the position for you. window.scrollTo({ top, behavior }) moves to an exact pixel position, and scrollBy moves by a relative amount. Use scrollTo when you already have a number, such as returning to a saved position.
window.scrollTo({ top: 0, behavior: 'smooth' }). For a scrollable panel, call the same method on the panel element instead of window.
Common causes are calling it before the element exists (run it after render, for example in a React effect), the element being display: none, or the nearest option with an element that is already fully visible.
Related: Sticky header guide, Scroll animations, CSS scroll snap, JavaScript event listeners, JavaScript loops compared.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.