The .offset() method gets or sets an element’s coordinates relative to the document as a PlainObject { top, left } — ideal for tooltips, click tracking, and drag-and-drop at page level. This tutorial covers getter and setter overloads, comparisons with .position(), .css("top")/.css("left"), and getBoundingClientRect(), callback setters since 1.4, and practical keyboard-move patterns.
01
Getter
.offset() → { top, left }
02
Setter
Since 1.4
03
Document
Page-relative
04
vs position
Offset parent
05
Callback
Since 1.4
06
Since 1.2
Getter API
Fundamentals
Introduction
After learning dimension methods like .height() and .innerWidth(), you often need to know where an element sits on the page — not just how big it is. jQuery’s .offset() returns a plain object with top and left pixel distances from the document origin, ready for math, logging, and repositioning without parsing CSS strings.
Available since jQuery 1.2 as a getter, .offset() gained setter and callback forms in jQuery 1.4. The getter reads document coordinates from the first matched element; the setter moves every matched element to new document coordinates. Unlike .position(), which is relative to the offset parent, .offset() always answers “where is this on the page?”
If you have worked with native DOM APIs, element.getBoundingClientRect() returns viewport-relative coordinates. To convert to document coords you add window.scrollX and window.scrollY. jQuery’s .offset() performs that style of calculation for you and wraps it in a familiar jQuery API with optional setter support.
Concept
Understanding the .offset() Method
Given a jQuery object, .offset() either returns the current document coordinates of the first matched element as a PlainObject { top, left } (getter), or repositions every matched element to the coordinates you pass (setter). Both values are numbers measured in pixels from the top-left corner of the document.
Think of .offset() as a GPS pin on the full page. .position() is a local map inside a positioned container. Use .offset() when placing overlays at click coordinates, aligning popovers to page landmarks, or moving draggable widgets with arrow keys — anywhere document-relative placement matters.
💡
Beginner Tip
A box inside #wrap { position: relative; margin: 40px; } might report .position() as { top: 0, left: 0 } but .offset() as roughly { top: 40, left: 40 } plus padding — because offset measures from the document, not the wrapper.
Foundation
📝 Syntax
jQuery .offset() has three argument forms — one getter and two setters:
Get — no arguments (since 1.2)
jQuery
.offset() // -> { top: Number, left: Number }
Returns a PlainObject with top and left from the first matched element.
Coordinates are relative to the document, not the viewport or offset parent.
Returns undefined when the jQuery set is empty.
Values may be fractional on sub-pixel or zoomed layouts.
Each tile shifts 24px further right based on its index — useful for fan-out animations and grid corrections without manual loops.
Return value
Getter — PlainObject { top, left }. Empty set → undefined.
Setter — the original jQuery object for chaining.
Important note
⚠️
Hidden elements
.offset() on display:none or hidden elements is unreliable — jQuery may return { top: 0, left: 0 }. Measure after showing the element, clone it off-screen, or use a visibility trick before reading.
Official jQuery API example
jQuery
var p = $( "p" ).last();
var offset = p.offset();
p.html( "left: " + offset.left + ", top: " + offset.top );
var o = $(this).offset(); alert(o.left + ", " + o.top)
Arrow-key move (read/write offset)
var o = $box.offset(); o.left += 10; $box.offset(o)
Compare
📋 .offset() vs .position() vs .css() vs getBoundingClientRect()
Four ways to read or write placement — document coords, offset-parent coords, raw CSS strings, and viewport-native rectangles.
💡
Which one should I use?
Need page-level placement or a setter? → .offset(). Layout inside a position: relative wrapper? → .position() getter. 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.
.offset()
document
Get/set { top, left } relative to the document — jQuery PlainObject
.position()
parent
Getter only — coords relative to offset parent; no setter
.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
.offset()
Document
Yes (1.4+)
{ top, left } PlainObject
.position()
Offset parent
No
{ 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
Examples 1–3 follow the official jQuery API documentation. Examples 4–5 compare .offset() with .position() and build keyboard-driven movement. Use DevTools or the Try-it links to run each snippet.
📚 Getting Started
Official jQuery demos for reading and setting document coordinates.
Example 1 — Official Demo: Get Last Paragraph Offset
Read the document left and top of the last <p> and display them in the paragraph.
jQuery
var p = $( "p" ).last();
var offset = p.offset();
p.html( "left: " + offset.left + ", top: " + offset.top );
left: ~26, top: ~48 (example — document coords of last <p>)
Getter returns PlainObject { top, left } from first matched element only
Values reflect body padding and paragraph margin-left: 10px
How It Works
No-argument .offset() returns a PlainObject with numeric top and left properties measured from the document origin. Only the first matched element is read when multiple elements are selected.
Example 2 — Official Demo: Click Any Element to Show Coords
Attach a click handler to every element in document.body and display its tag name with document offset.
Click P -> P coords ( ~26, ~72 )
Click SPAN -> SPAN coords ( ~26, ~96 )
Click green div -> DIV coords ( ~220, ~35 ) — position:absolute
stopPropagation() prevents parent handlers from overwriting #result
How It Works
$(this).offset() gives document coordinates for whichever element was clicked — paragraphs, spans, or an absolutely positioned box. event.stopPropagation() keeps nested clicks from bubbling to parent handlers.
Example 3 — Official Demo: Set Offset with { top: 10, left: 30 }
Reposition the last paragraph to document coordinates top: 10, left: 30 on page load.
Last paragraph jumps near top-left of document (10px from top, 30px from left)
Setter support arrived in jQuery 1.4
Static paragraphs get position:relative applied internally by jQuery
How It Works
.offset({ top: 10, left: 30 }) moves the element so its top-left corner sits at those document coordinates. jQuery may set position: relative on static elements to achieve the placement. The setter returns the jQuery object for chaining.
📈 Practical Patterns
Compare placement APIs and build keyboard-driven repositioning.
Example 4 — Compare .offset() and .position() 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 5 — Arrow Keys Move Box with .offset() Setter
Read current document coords, adjust by 10px per arrow key, and write back with the setter — a simple drag-and-drop alternative.
jQuery
var step = 10;
$( document ).on( "keydown", function( e ) {
var $box = $( "#box" );
var o = $box.offset();
if ( e.key === "ArrowLeft" ) o.left -= step;
if ( e.key === "ArrowRight" ) o.left += step;
if ( e.key === "ArrowUp" ) o.top -= step;
if ( e.key === "ArrowDown" ) o.top += step;
if ( /Arrow/.test( e.key ) ) {
e.preventDefault();
$box.offset( o );
}
});
ArrowLeft -> left decreases by 10px
ArrowRight -> left increases by 10px
ArrowUp -> top decreases by 10px
ArrowDown -> top increases by 10px
Read .offset(), mutate o.left/o.top, write with .offset(o)
How It Works
This read-modify-write pattern is the core of many drag helpers: getter returns current document position, you adjust numbers, setter applies the new coords. For mouse dragging, run the same logic on mousemove with pointer coordinates minus element dimensions.
💡
Drag-and-drop tip
On mousedown, store var start = $el.offset() and pointer start. On mousemove, compute deltaX/deltaY and call $el.offset({ top: start.top + deltaY, left: start.left + deltaX }). Use Math.round() if you need pixel-perfect integer steps.
Applications
🚀 Common Use Cases
Click coordinate logging — $(this).offset() on click to show where the user hit an element on the page.
Tooltip and popover placement — position overlays at document coords derived from a trigger’s .offset() plus width/height.
Drag-and-drop helpers — read .offset(), update on mousemove, write with the setter (see Example 5).
Keyboard nudging — arrow-key handlers that increment/decrement top and left in fixed steps.
Layout debugging — compare .offset() and .position() to trace offset-parent vs document mismatches.
Absolute repositioning — .offset({ top: 10, left: 30 }) to snap widgets to known document landmarks on load.
Scroll-aware overlays — combine trigger .offset() with .outerHeight() / .outerWidth() to anchor menus below buttons.
jQuery object holds DOM elements to measure or move.
Input
2
Detect mode
No args → getter. Object or function → setter on each element (1.4+).
Route
3
Measure or apply
Getter walks offset-parent chain to document. Setter may set position: relative on static elements, then applies top/left.
DOM
4
📍
Return result
Getter → PlainObject { top, left } (or undefined if empty). Setter → same jQuery object for chaining.
Important
📝 Notes
Getter available since jQuery 1.2 — setter and callback since 1.4.
Getter returns PlainObject { top, left } from the first matched element only.
Coordinates are document-relative, not viewport-relative (contrast getBoundingClientRect()).
Setter on position: static elements internally applies position: relative.
.position() is offset-parent-relative and has no setter — do not confuse the two.
Empty jQuery set → getter returns undefined.
Unreliable on hidden (display:none) elements — may return { top: 0, left: 0 }.
Values can be fractional (e.g. 82.5) on sub-pixel or zoomed displays.
Setter returns the original jQuery object — e.g. .offset(o).addClass("moved").
Compatibility
Browser Support
.offset() getter has been part of jQuery since 1.2+. Setter and callback forms arrived in 1.4+. It wraps cross-browser document coordinate math with no browser-specific quirks beyond jQuery itself.
✓ jQuery 1.2+
jQuery .offset()
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery builds. Native equivalent: getBoundingClientRect() plus scroll offsets for document coords — jQuery adds collection semantics, PlainObject returns, setter support, and callback chaining.
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
.offset()Universal
Bottom line: Safe in any jQuery project. Use .offset() for document placement; use .position() inside positioned containers; use getBoundingClientRect() when viewport coords suffice.
Wrap Up
Conclusion
The jQuery .offset() method gets or sets document coordinates as a PlainObject { top, left } — the right placement helper when you need page-level position for clicks, tooltips, and drag-and-drop. It complements dimension methods like .innerWidth() and contrasts with .position(), which is local to the offset parent.
Remember the official demo: $( "p" ).last().offset() reads document coords, and the setter .offset({ top: 10, left: 30 }) repositions elements anywhere on the page. Use the callback form to nudge each element independently, and pair read-modify-write .offset() calls for keyboard or mouse movement — but never trust readings from display:none elements without showing them first.
Use .offset() when you need document-relative coordinates
Use .position() for layout inside a positioned container
Read-modify-write .offset() for keyboard nudging and simple drags
Use the callback setter to adjust each matched element independently
Set position explicitly in CSS when you need long-term control
❌ Don’t
Confuse .offset() with .position() — different reference frames
Trust .offset() on display:none elements — it may return zeros
Expect the getter to read all matched elements — only the first
Assume .css("top") equals document coords — it returns CSS strings
Forget that an empty jQuery set returns undefined from the getter
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about .offset()
Document coordinates — ready for placement.
6
Core concepts
#01
Getter
1.2+
Read
=02
Setter
1.4+
Write
doc03
Document
Page coords
Frame
fn04
Callback
1.4+
Index
pos05
vs position
Parent rel
Compare
hide06
Hidden
Unreliable
Caveat
❓ Frequently Asked Questions
Calling .offset() with no arguments is the getter — it returns a PlainObject { top, left } with the current coordinates of the first matched element relative to the document. Calling .offset({ top, left }) or .offset(function) is the setter — it repositions every matched element in the document and returns the original jQuery object for chaining. The getter has been available since jQuery 1.2; setters and the callback form arrived in jQuery 1.4.
.offset() measures distance from the document origin (top-left of the page, ignoring scroll only in the sense that it accounts for document layout). .position() measures distance from the element's offset parent — usually the nearest positioned ancestor. An element inside a position:relative wrapper may have .position() { top: 0, left: 0 } while .offset() returns much larger document coordinates. Use .offset() for page-level placement; use .position() for layout inside a positioned container.
jQuery temporarily sets position: relative on elements that are position: static before applying top and left values derived from your target coordinates. That is how the setter can move elements that were not already positioned. If you need long-term CSS control, set position explicitly yourself and prefer .css('top') / .css('left') or .position() for offset-parent-relative moves.
No — .offset() on display:none or otherwise non-rendered elements is unreliable and may return { top: 0, left: 0 } or incorrect values because the browser has not laid out the element. Temporarily show the element, clone it off-screen, or measure after making it visible before trusting getter results.
Yes — since jQuery 1.4, .offset(function(index, coords)) receives the zero-based index and the element's current { top, left } object; return a new coords object to reposition each element independently. Getter and setter coordinates can be fractional (e.g. 82.5) on sub-pixel layouts, zoomed displays, or transformed elements; use Math.round() when you need integer steps for keyboard or grid movement.
.offset() is ideal when you need document-relative coordinates — for example, reading where the user clicked, placing a tooltip at page coordinates, or moving a draggable box with arrow keys by reading current .offset(), adjusting top/left, and writing back with the setter. For drag inside a scrollable or positioned container, combine .offset() with scroll offsets or prefer .position() relative to the offset parent. Modern alternatives include getBoundingClientRect() plus scroll math, but .offset() remains the jQuery-native shortcut.
Did you know?
jQuery’s .offset() getter has existed since version 1.2 — setters and callbacks arrived in 1.4. When you call the setter on a position: static element, jQuery temporarily promotes it to position: relative so top and left can take effect. That is why a paragraph can jump to { top: 10, left: 30 } without you writing CSS first. The callback setter mirrors .css() dimension callbacks — return a different { top, left } per index for staggered placement. For viewport-only math, native getBoundingClientRect() is often enough; add window.scrollX and scrollY when you need document coords without jQuery.