Skip to content

[cssom-view-1] offsetParent spec says that we return elements from open shadow trees, no browser does. #12392

Open

Description

@flackr

According to the cssom-view-1 spec, offsetParent should expose a containing element within an open shadow tree, however, on testing it seems that chrome, firefox and safari skip the shadow tree entirely.

If ancestor is not closed-shadow-hidden from the element and satisfies at least one of the following, terminate this algorithm and return ancestor.

See https://jsbin.com/negusux/edit?html,js,output
In particular, I think the offsetParent of <DIV id="openInnerElement" class="target"> should be the .shadow-scroller element in the <open-component> if browsers were following the spec, however every browser returns the same <DIV id="outerScroller" class="scroller"> for both the open and closed shadow trees, skipping the shadow tree entirely.

I propose we update the spec to match what browsers do, skipping elements from inner shadow trees, for both offsetParent and the new scrollParent.

@tabatkins FYI

Activity

  1. emilio commented on Oct 1, 2025

    @emilio
    Collaborator

    Sounds good to me fwiw.

  2. css-meeting-bot commented on Oct 8, 2025

    @css-meeting-bot
    Member

    The CSS Working Group just discussed [cssom-view-1] offsetParent spec says that we return elements from open shadow trees, no browser does., and agreed to the following:

    • RESOLVED: Make offsetParent spec match reality
    • ACTION: flackr to open issue on making scrollParent a function
    • ACTION: dbaron to open an issue on replacements for offsetParent
    The full IRC log of that discussion <fantasai> scribe+
    <lea> q?
    <emilio> flackr: As I was implementing scrollParent I discovered that the spec for offsetParent claims we should expose elements within open shadow trees yet no impl does that
    <lea> q+
    <emilio> ... I'd like to resolve to change it to match implementations and do the same for scrollParent
    <emilio> q+
    <astearns> ack lea
    <emilio> lea: is there a reason for what browsers do?
    <lea> q+
    <fantasai> emilio: implementation-wise it's the same, but I don't think any DOM API distinguishes between both
    <fantasai> emilio: DOM event targetting etc. works the same in open vs closed shadow root
    <masonf> +1
    <fantasai> emilio: So I think it's best to not differentiate here either
    <fantasai> emilio: for APIs where you might want to get things from shadow roots, we've added option to pass shadow roots to have access to
    <fantasai> emilio: that way you can access both closed and open shadow roots depending on what you have access to
    <emilio> lea: what do they actually return?
    <astearns> ack lea
    <emilio> ... do they return the host or do they skip that element?
    <emilio> flackr: they skip to the shadow host but it might traverse further up if the shadow host doesn't meet the requirements
    <emilio> lea: the current behavior seems more useful
    <emilio> ... wondering if we could also add a corresponding property that does the right thing
    <emilio> q+
    <oriol> q+
    <astearns> ack emilio
    <astearns> ack oriol
    <fantasai> emilio: Could add an argument to do it consistently in the DOM, but I don't think it should be specific to offsetParent APIs
    <flackr> +1
    <lea> s/lea: the current behavior seems more useful/lea: the current behavior seems more useful, but I also understand the web compat argument of speccing what browsers already do/
    <emilio> oriol: I think scrollParent should be a function to allow eventual extensions?
    <astearns> ack dbaron
    <lea> +1 oriol
    <emilio> dbaron: I think we should be looking at offset* as a legacy API
    <emilio> ... I think the implementation of these existed well before the spec did
    <emilio> ... in general we want to bias towards specifying what's implemented
    <emilio> ... to some degree we have various APIs that are trying to replace them
    <emilio> ... some of that is implemented like getBoundingClientRect and other pieces in the geometry spec?
    <masonf> examples: innerHTML --> getHTML(), getRangeAt() --> getComposedRanges(), etc.
    <emilio> ... not sure what the state of all of them are?
    <lea> q?
    <lea> q+
    <emilio> ... I would not try and improve offset*
    <emilio> ... I'd try and build the API we want more generally
    <astearns> ack lea
    <emilio> q+
    <emilio> lea: I agree these are weird and fine to treat them as legacy
    <emilio> ... but not sure what'd be the replacement
    <emilio> ... is there an API that could replace them today?
    <astearns> ack emilio
    <fantasai> emilio: [missed]
    <fantasai> emilio: The consistent thing to do is to not distinguish between open and closed shadow roots
    <lea> many scripts were written before shadows were a thing and use these properties for positioning and ideally should not break too badly when dropped into a page that has shadow roots
    <masonf> q+
    <fantasai> emilio: We can decide to use a function for scoped parent or add a new function for passing list of shadow roots or whatever
    <astearns> s/[missed]/yes these things were implemented before being specced, but shadow root came after the spec
    <fantasai> emilio: but big +1 to spec what's implemented for offsetParent because it's the right thing to do
    <astearns> ack masonf
    <Kurt> +1 emilio
    <fantasai> emilio: consistent with the way it works elsewhere in DOM
    <lea> q?
    <lea> q+
    <emilio> masonf: I commented with some precedent on the DOM side (innerHTML / getHTML() / etc)
    <astearns> ack lea
    <emilio> ... not a technical issue, just a consistency argument
    <emilio> lea: Fine to spec what's implemented, but we should work to close the gap because there's no way of doing what the spec says
    <emilio> dbaron: yeah it'd be good to have some element-to-element coord space conversion
    <emilio> PROPOSED: Fix offsetParent by spec-ing reality, but work into a way to opt into looking into shadow roots
    <emilio> q+
    <kbabbitt> +1
    <lea> (though hopefully anchor positioning renders many of the use cases for these properties obsolete)
    <masonf> +1
    <lea> +1
    <astearns> ack emilio
    <fantasai> emilio: We should definitely update offsetParent.
    <oriol> It's implemented in Blink and Servo
    <fantasai> emilio: scrollParent is not implemented anywhere, so maybe we can make it functional already
    <fantasai> flackr: We have an implementation, but not shipped yet
    <fantasai> emilio: fair
    <emilio> RESOLVED: Make offsetParent spec match reality
    <dbaron> I think some of what I'm thinking of was for a time in a GeometryUtils interface in https://drafts.fxtf.org/geometry/#geometryutils
    <emilio> astearns: if we make scrollParent a function we can allow passing a list of shadow roots
    <emilio> flackr: I see
    <emilio> astearns: we should file an issue for that
    <fantasai> ACTION: flackr to open issue on making scrollParent a function
    <emilio> astearns: we should look into whether appropriate replacements for offsetParent exist
    <fantasai> ACTION: dbaron to open an issue on replacements for offsetParent
  3. Loirooriol commented on Feb 12, 2026

    @Loirooriol
    Contributor

    ACTION: flackr to open issue on making scrollParent a function

    This was resolved in #12731 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions