The .position() method reads an element’s coordinates relative to its offset parent as a PlainObject { top, left } — ideal for layout inside positioned containers, aligning widgets near siblings, and keyboard nudging within a stage. This tutorial covers the getter-only API since jQuery 1.2, how to move elements with .css("top")/.css("left") when no setter exists, comparisons with .offset(), .css(), and getBoundingClientRect(), and practical measurement patterns.
01
Getter
.position() → { top, left }
02
No setter
Use .css()
03
Parent
Offset parent
04
vs offset
Document coords
05
Local layout
Same container
06
Since 1.2
Getter API
Fundamentals
Introduction
After learning document coordinates with .offset(), you often need placement inside a positioned wrapper — a modal panel, a game stage, or a relatively positioned sidebar. jQuery’s .position() returns a plain object with top and left pixel distances from the element’s offset parent, ready for local math without converting from page coordinates.
Available since jQuery 1.2, .position() is a getter with no arguments and no setter overload. It reads offset-parent coordinates from the first matched element only. Unlike .offset(), which always answers “where is this on the page?”, .position() answers “where is this inside its containing positioned element?” — more useful when positioning one element near another within the same DOM subtree.
If you have worked with native DOM APIs, remember that getBoundingClientRect() returns viewport-relative coordinates. jQuery’s .position() is neither document-relative nor viewport-relative — it is local to the offset parent’s padding box. For page-level placement or a built-in setter, use .offset() instead.
Concept
Understanding the .position() Method
Given a jQuery object, .position() returns the current offset-parent coordinates of the first matched element as a PlainObject { top, left }. Both values are numbers measured in pixels from the padding edge of the offset parent to the margin edge of the element.
Think of .position() as a local map inside a positioned container. .offset() is a GPS pin on the full page. Use .position() when aligning a tooltip arrow to a chip inside a panel, nudging a draggable box within a stage, or listing tile coordinates in a grid — anywhere offset-parent-relative placement matters.
💡
Beginner Tip
A box inside #wrap { position: relative; padding: 20px; } might report .position() as { top: 0, left: 0 } at the padding origin, while .offset() returns much larger document coordinates that include the wrap’s margin and the page scroll position.
Foundation
📝 Syntax
jQuery .position() has one form — a getter with no arguments:
Get — no arguments (since 1.2)
jQuery
.position() // -> { top: Number, left: Number }
Returns a PlainObject with top and left from the first matched element.
Coordinates are relative to the offset parent (padding box of parent, margin box of element).
Returns undefined when the jQuery set is empty.
Values may be fractional on sub-pixel or zoomed layouts.
Does not support hidden elements; does not account for margins on the html element.
How to move without a setter
Because .position() has no setter, reposition elements with explicit CSS:
jQuery
// 1. Ensure the element is positioned
$el.css( "position", "absolute" );
// 2. Read current local coords, adjust, write back
var p = $el.position();
p.left += 10;
$el.css({ top: p.top, left: p.left });
Set position: absolute or position: relative so top and left take effect.
Read with .position(), mutate the numbers, write with .css({ top, left }).
For document-level moves, use .offset({ top, left }) setter instead (since 1.4).
Return value
Getter — PlainObject { top, left }. Empty set → undefined.
No setter — passing arguments has no effect; jQuery does not provide .position({ top, left }).
Important note
⚠️
Hidden elements
.position() does not support hidden (display:none) elements — readings are unreliable because the browser has not laid out the element. Measure after showing the element, clone it off-screen, or defer measurement until visibility is restored.
Official jQuery API example
jQuery
var p = $( "p" ).first();
var position = p.position();
$( "p" ).last().text( "left: " + position.left + ", top: " + position.top );
Cheat Sheet
⚡ Quick Reference
Goal
Code
Read offset-parent coordinates (PlainObject)
$("div").position()
Move element inside offset parent
var p = $("div").position(); p.left += 10; $("div").css({ top: p.top, left: p.left })
Ensure element can be moved with top/left
$("div").css("position", "absolute")
Coords relative to document
$("div").offset()
Read CSS top/left strings
$("div").css("top")
Viewport rect (native)
el.getBoundingClientRect()
Show click target local coords
var p = $(this).position(); alert(p.left + ", " + p.top)
Arrow-key move inside stage
var p = $box.position(); p.left += 10; $box.css({ top: p.top, left: p.left })
Compare
📋 .position() vs .offset() vs .css() vs getBoundingClientRect()
Four ways to read or write placement — offset-parent coords, document coords, raw CSS strings, and viewport-native rectangles.
💡
Which one should I use?
Layout inside a position: relative wrapper or same containing element? → .position() getter. Need page-level placement or a setter? → .offset(). Need the literal CSS value "auto" or "50%"? → .css("top"). Building without jQuery and only care about viewport? → getBoundingClientRect() plus scroll offsets for document coords.
.position()
parent
Getter only — coords relative to offset parent; no setter
.offset()
document
Get/set { top, left } relative to the document — jQuery PlainObject
.css()
"10px"
General CSS getter/setter — top/left return strings with units or auto
getBoundingClientRect()
viewport
Native DOMRect vs viewport — add scroll offsets for document coords
Method
Reference frame
Setter?
Return type
.position()
Offset parent
No
{ top, left } PlainObject
.offset()
Document
Yes (1.4+)
{ top, left } PlainObject
.css("top")
CSS cascade
Yes
String ("10px", "auto")
getBoundingClientRect()
Viewport
No (read-only)
DOMRect (top, left, width, height)
Hands-On
Examples Gallery
Example 1 follows the official jQuery API documentation inside a padded container. Examples 2–5 compare .position() with .offset(), log chip coords on click, move a box with arrow keys inside a stage, and enumerate grid tile positions. Use DevTools or the Try-it links to run each snippet.
📚 Getting Started
Official jQuery demo for reading offset-parent coordinates inside a padded div.
Example 1 — Official Demo: Get First Paragraph Position
Read the offset-parent left and top of the first <p> and display them in the last paragraph inside a padded div.
jQuery
var p = $( "p" ).first();
var position = p.position();
$( "p" ).last().text( "left: " + position.left + ", top: " + position.top );
left: ~20, top: ~20 (example — offset-parent coords of first <p>)
Getter returns PlainObject { top, left } from first matched element only
Values reflect padded div origin (padding box of offset parent)
How It Works
No-argument .position() returns a PlainObject with numeric top and left properties measured from the offset parent’s padding edge. Only the first matched element is read when multiple elements are selected.
📈 Practical Patterns
Compare placement APIs, log local coords on click, and build keyboard-driven movement inside containers.
Example 2 — Compare .position() and .offset() in #wrap
See how a relatively positioned wrapper changes .position() but not the document meaning of .offset().
.offset() -> left: ~66, top: ~66 (document — includes wrap margin + padding)
.position() -> left: 0, top: 0 (inside #wrap offset parent)
Same element, two reference frames — pick the one your layout needs
How It Works
.offset() always reports document coordinates. .position() reports placement inside the nearest offset parent — here #wrap with position: relative. The box sits at the origin of its parent locally, but far from the document origin globally.
Example 3 — Click Chips in #panel to Show Position
Attach click handlers to chip elements and display each chip’s offset-parent coordinates inside the panel.
Click Alpha -> Alpha position ( ~12, ~48 )
Click Beta -> Beta position ( ~72, ~48 )
Click Gamma -> Gamma position ( ~132, ~48 )
Coords are relative to #panel offset parent, not the document
How It Works
$(this).position() gives local coordinates for whichever chip was clicked — ideal when aligning a tooltip or highlight to the clicked chip inside the same panel without converting from document coords.
Example 4 — Arrow Keys Move Box Inside #stage via .position() + .css()
Read current offset-parent coords, adjust by 10px per arrow key, and write back with .css() — the standard pattern when no setter exists.
jQuery
var step = 10;
$( document ).on( "keydown", function( e ) {
var $box = $( "#box" );
var p = $box.position();
if ( e.key === "ArrowLeft" ) p.left -= step;
if ( e.key === "ArrowRight" ) p.left += step;
if ( e.key === "ArrowUp" ) p.top -= step;
if ( e.key === "ArrowDown" ) p.top += step;
if ( /Arrow/.test( e.key ) ) {
e.preventDefault();
$box.css({ top: p.top, left: p.left });
}
});
ArrowLeft -> left decreases by 10px inside #stage
ArrowRight -> left increases by 10px inside #stage
ArrowUp -> top decreases by 10px inside #stage
ArrowDown -> top increases by 10px inside #stage
Read .position(), mutate p.left/p.top, write with .css({ top, left })
How It Works
This read-modify-write pattern is the core of in-container movement: getter returns current offset-parent position, you adjust numbers, .css() applies the new coords. The box stays bounded relative to #stage rather than the full document — unlike an .offset() setter approach.
💡
Stage movement tip
Ensure #box { position: absolute; } inside #stage { position: relative; } so top and left are meaningful. Use Math.round() on p.top and p.left if you need pixel-perfect integer steps.
Example 5 — List Tile Positions in #grid
Loop over grid tiles and log each tile’s .position() relative to the grid container.
jQuery
var lines = [];
$( "#grid .tile" ).each( function( i ) {
var pos = $( this ).position();
lines.push( "Tile " + ( i + 1 ) + ": left " + pos.left + ", top " + pos.top );
});
$( "#out" ).html( lines.join( " " ) );
Tile 1: left 0, top 0
Tile 2: left 80, top 0
Tile 3: left 0, top 80
Tile 4: left 80, top 80
Each tile measured relative to #grid offset parent — useful for layout debugging
How It Works
Calling .position() inside .each() reads the first (and only) element in each jQuery wrapper, giving per-tile local coordinates. Compare with .offset() if you need document coords for drag-and-drop across the page.
Applications
🚀 Common Use Cases
Local click coordinate logging — $(this).position() on click to show where the user hit an element inside a panel.
Tooltip and popover alignment — position overlays relative to a trigger’s .position() plus width/height inside the same container.
In-container drag helpers — read .position(), update on mousemove, write with .css({ top, left }) (see Example 4).
Keyboard nudging inside a stage — arrow-key handlers that increment/decrement local top and left without affecting document coords.
Layout debugging — compare .position() and .offset() to trace offset-parent vs document mismatches.
Grid and tile enumeration — loop tiles and log each .position() to verify flex or float layout (see Example 5).
Relative widget placement — position one element near another within the same containing DOM element without scroll math.
Animation starting points — capture local coords before .animate({ top, left }) for in-container motion paths.
🧠 How .position() Reads Offset-Parent Coordinates
1
Match elements
jQuery object holds DOM elements to measure.
Input
2
Find offset parent
jQuery walks ancestors to locate the nearest offset parent (positioned ancestor or body).
Route
3
Measure local offset
Compute distance from parent padding box to element margin box. Hidden elements are not supported.
DOM
4
📍
Return result
Getter → PlainObject { top, left } from first element (or undefined if empty). No setter — use .css() to move.
Important
📝 Notes
Getter available since jQuery 1.2 — no arguments, no setter, no callback.
Getter returns PlainObject { top, left } from the first matched element only.
Coordinates are offset-parent-relative, not document-relative (contrast .offset()).
Measured from offset parent padding box to element margin box.
Does not account for margins on the html element.
Empty jQuery set → getter returns undefined.
Does not support hidden (display:none) elements — readings are unreliable.
Values can be fractional (e.g. 82.5) on sub-pixel or zoomed displays; zoom may affect accuracy.
To move elements, set position in CSS and use .css("top") / .css("left").
Compatibility
Browser Support
.position() getter has been part of jQuery since 1.2+. It wraps cross-browser offset-parent coordinate math with no browser-specific quirks beyond jQuery itself.
✓ jQuery 1.2+
jQuery .position()
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery builds. Native equivalent: walk offsetParent chain or use getBoundingClientRect() with ancestor math — jQuery adds collection semantics and PlainObject returns.
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.position()Universal
Bottom line: Safe in any jQuery project. Use .position() inside positioned containers; use .offset() for document placement; use .css() to write top/left when moving locally.
Wrap Up
Conclusion
The jQuery .position() method reads offset-parent coordinates as a PlainObject { top, left } — the right placement helper when you need local position inside a positioned container for chips, stages, and grids. It complements document-level .offset() and contrasts with .css("top"), which returns CSS strings rather than computed local coords.
Remember the official demo: $( "p" ).first().position() reads offset-parent coords inside a padded div, and the last paragraph displays them. Because there is no setter, move elements with .css({ top, left }) after reading .position() — but never trust readings from hidden elements without showing them first.
Use .position() for layout inside a positioned container
Use .offset() when you need document-relative coordinates or a setter
Read-modify-write .position() + .css() for in-container keyboard nudging
Set position: absolute or relative before writing top/left
Compare .position() and .offset() when debugging layout mismatches
❌ Don’t
Confuse .position() with .offset() — different reference frames
Expect a setter — .position({ top, left }) does not exist
Trust .position() on hidden elements — jQuery does not support them
Expect the getter to read all matched elements — only the first
Assume .css("top") equals local coords — it returns CSS strings like "auto"
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about .position()
Offset-parent coordinates — ready for local layout.
6
Core concepts
#01
Getter
1.2+
Read
x02
No setter
Use .css()
Move
par03
Parent
Offset parent
Frame
off04
vs offset
Document
Compare
box05
Margin box
Padding origin
Measure
hide06
Hidden
Unsupported
Caveat
❓ Frequently Asked Questions
The offset parent is the nearest ancestor element used as the reference frame for .position(). It is usually the closest ancestor with position: relative, absolute, fixed, or sticky — or the document body if none qualify. .position() returns { top, left } measured from the padding edge of that offset parent to the margin edge of the element. Understanding which element is the offset parent explains why two siblings can share the same .position() origin inside a positioned wrapper.
.position() measures distance from the offset parent — ideal when positioning one element near another inside the same containing DOM element. .offset() measures distance from the document origin (page-level coordinates). An element at the top-left corner of a position:relative wrapper may report .position() { top: 0, left: 0 } while .offset() returns much larger document coordinates that include margins, padding, and ancestor offsets. Use .position() for local layout; use .offset() for page-level placement.
.position() is getter-only. To reposition an element relative to its offset parent, set position explicitly in CSS (position: absolute or relative) and use .css('top', value) and .css('left', value). A common pattern is read-modify-write: var p = $el.position(); p.left += 10; $el.css({ top: p.top, left: p.left }). For document-level moves, use .offset() setter instead. Never expect .position({ top, left }) to work — jQuery does not provide that overload.
No — jQuery does not support .position() on hidden (display:none or otherwise non-rendered) elements. The browser has not laid out the element, so readings are unreliable and may be wrong or zero. Temporarily show the element, clone it off-screen, or measure after making it visible before trusting getter results. The same caution applies to .offset() on hidden elements.
According to the jQuery API, .position() calculates coordinates relative to the offset parent, using the offset parent's padding box as the origin and the element's margin box as the measured edge. That means parent padding shifts the local origin inward, and the element's own margin is included in the reported top/left. jQuery also does not account for margins on the html element when walking the offset-parent chain — a subtle edge case on full-page layouts.
Yes — .position() may return fractional numbers (e.g. 82.5) on sub-pixel layouts, zoomed displays, or transformed elements. Browser zoom can affect accuracy. Use Math.round() when you need integer steps for keyboard movement or grid snapping. An empty jQuery set returns undefined from the getter, not a coords object.
Did you know?
jQuery’s .position() getter has existed since version 1.2 — with no setter overload ever added. Coordinates are measured from the offset parent’s padding box to the element’s margin box, which is why parent padding shifts the local origin. jQuery deliberately does not account for margins on the html element when walking the chain. Fractional values like 82.5 are normal on zoomed or sub-pixel layouts. When you need document-level placement or a one-call setter, reach for .offset() instead — but for positioning one widget near another inside the same panel or stage, .position() keeps the math local and simple.