How do I get the (x,y) position of an HTML element?

Richard C.

The Problem

How do you find the (x, y) coordinate of an HTML element on your page? You might want to position a popup next to an element, create a fancy animation, or overlay elements seamlessly.

The Solution

There are two coordinate systems in HTML:

  • The coordinates of the entire page (parts of which may be completely off the screen).
  • The coordinates of the elements shown in the window (the user’s current viewport).

Let’s call these page coordinates and window coordinates. Both of these axes have their origin points (0,0) at the top left of the page or window, with values increasing towards the bottom right.

Get the Window Coordinate

To get the position of an HTML element in JavaScript relative to the window, use getBoundingClientRect():

<!DOCTYPE html> <html lang=""> <body> <div id="myElement" style="position: absolute; left: 50px; top: 100px;"> Hello World </div> <script> globalThis.setInterval(() => { const element = document.getElementById("myElement"); const rect = element.getBoundingClientRect(); console.log("X: " + rect.x + ", Y: " + rect.y); }, 1000); </script> </body> </html>

In this code, we call getBoundingClientRect() on an element positioned manually at (50,100). This returns a rectangle object, whose properties are the x and y coordinates we need. The interval timer will write a new value to the console every second.

The DOMRect object provides the following properties for your element: left, top, right, bottom, x, y, width, and height.

Although you can set negative values in CSS, getBoundingClientRect() always returns positive width and height values. The left and x values are the same, as are the top and y values — as long as no CSS transform has been applied to the element (more on that later).

The height and width values include the element’s border and padding, but not its margin value. To calculate the full height of an element you need to access its CSS:

let style = getComputedStyle(element); let marginTop = parseFloat(style.marginTop); let marginBottom = parseFloat(style.marginBottom);

Get the Page Coordinate

Using getBoundingClientRect(), the position of the div will change whenever you scroll on the page. If you want to get the absolute position of the element on the page, not relative to the window, add the number of scrolled pixels to the element’s window location using scrollY:

console.log("X: " + (rect.x + globalThis.scrollX) + ", Y: " + (rect.y + globalThis.scrollY));

The parentheses around the sums are added for JavaScript to treat them as numbers and not concatenate them as strings.

Handle Other Complexities

If you have a complex page layout, such as one with containers with their own scroll windows (div with overflow: scroll), or one using CSS transformations, you may need to use other element properties to calculate the x and y positions.

First, define what the position of an element means in your layout. Is it relative to the page, the window, or another element on the page? It’s likely you still need only the window position of the element to position another element next to it.

The following properties of an element may be useful to you (all are in pixels):

  • offsetParent — The closest positioned ancestor element that is not static (the default positioning type).
  • offsetLeft and offsetTop — The distance from the outer border of the current element (including its margin) to the padding edge of the offsetParent.
  • scrollHeight — The total height of a scrollable element, including the children not visible in the current view that you have to scroll down to see.
  • scrollTop — The distance from the top of a scrollable element that the user has scrolled down to. If the scrollbar is still at the top of the element then scrollTop is 0.
  • clientHeight — The height of a scrollable element visible on the page.

The getBoundingClientRect().height property of an element is different from its clientHeight. The clientHeight property includes the content and its padding but not its border, margin, or horizontal scrollbar. The getBoundingClientRect().height property includes the height of the content, padding, scrollbar, and borders, but not the margin.

You can loop through every offsetParent of an element until you return to the HTML body. If you sum all the offsetTop values along the way, you’ll have the total distance of the element from the start of the page. This will equal rect.y + globalThis.scrollY from earlier.

CSS Transforms

A transform is a CSS setting like transform: translate(5px, 6px);. A transform changes the position of an element visually, but not its original layout position in the document flow.

If an element has been moved with a transform, then getBoundingClientRect() will return left and top values from before the translation, and x and y values from after the translation — where the element appears to be visually. So you probably want to use the x and y values.

If you need to access the exact values of a transform, you can use getComputedStyle():

const transform = window.getComputedStyle(element).getPropertyValue('transform'); if (transform !== 'none') { const matrixValues = transform.match(/matrix.*\((.+)\)/)[1].split(', '); const tx = parseFloat(matrixValues[4]); const ty = parseFloat(matrixValues[5]); console.log('Shifted x by ' + tx); console.log('Shifted y by ' + ty); }

The transform object will be a string, like matrix(1, 0, 0, 1, 5, 6), so we need to extract its values using a regex match. The last two values are the x and y translation values. If you are using a 3D transformation with matrix3d, you need to adjust the regex.

A CSS transform also might involve scaling, rotation, and shearing, which will affect the visual appearance of the element in the window, but not its starting position.

Get Started With Sentry

Get actionable, code-level insights to resolve JavaScript performance bottlenecks and errors.

  1. Create a free Sentry account

  2. Create a JavaScript project and note your DSN

  3. Grab the Sentry JavaScript SDK

<script src="https://browser.sentry-cdn.com/7.112.2/bundle.min.js"></script>
  1. Configure your DSN
Sentry.init({ dsn: 'https://<key>@sentry.io/<project>' });

Loved by over 4 million developers and more than 90,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.

Share on Twitter
Bookmark this page
Ask a questionJoin the discussion

Related Answers

A better experience for your users. An easier life for your developers.

    TwitterGitHubDribbbleLinkedinDiscord
© 2024 • Sentry is a registered Trademark
of Functional Software, Inc.