Skip to content

Improve DX of element reference attributes by allowing relative references instead of only ids #10143

Open

Description

@LeaVerou

Edit: Explainer Draft


Problem statement

Many HTML attributes need to reference one or more HTML elements in the document. This includes:

  • Popovers (popovertarget)
  • Invokers (invoketarget)
  • A host of ARIA attributes (e.g. aria-describedby, aria-labelledby, aria-activedescendant, aria-controls, aria-details, aria-flowto, aria-owns etc.)
  • for, in <label> and <output>
  • list in <input>
  • the new anchor attribute

It is also a frequent use case in author web components as well, with WC authors coming up with wildly inconsistent solutions because they are forced to choose between ergonomics and consistency with the web platform. Most copy HTML as a source of truth and good design decisions, which makes the problem worse.

Currently, the only way to specify such references is to give these elements ids (if they don't already have them) and using these ids to link to them in these attributes.

This imposes high friction (especially when not using tooling to generate HTML), as authors then need to come up with suitable ids for elements that wouldn't otherwise have one and manually do the linking (and as we know, naming things is one of the hardest things in Computer Science 😁 ). It also introduces error conditions, as it is a common authoring mistake to change an id and forgetting to change the id references to it, pasting a chunk of HTML and forgetting to edit all the references, or ending up with broken references due to accidental duplicate ids.

This is a very common author pain point, and authors are pretty vocal about it: DX-related complaints were the 3rd biggest a11y complaint in the preliminary State of HTML results. It especially hurts a11y, since the effects of broken references in the a11y tree are not always obvious, and the more friction it takes to make HTML accessible, the less likely authors are to do it. And while for <label> this is somewhat mitigated by the option to make the association implicitly by nesting the form control within the <label>, for the other cases there is no similar option.

Being able to link to elements in a way that is relative to the element the attribute is specified on would solve all of these issues, and make writing ARIA much more pleasant.

Some considerations are:

  • The migration path for authors. It would introduce an undesirable cliff, if using a relative reference suddenly requires changing all of their existing absolute references. The more substantial the edit required, the sharper the cliff.
  • Not all use cases require relative references, so ideally the syntax should allow mixing the two. While a11y-related use cases tend to primarily need relative references, attributes like list need both (e.g. a "country" field would need to autocomplete to the same list of countries everywhere).

Relative reference use cases

More research is needed here, but in my experience most relative use cases are pretty simple paths from the current element to the one being referenced. Things like:

  1. Go N levels up (usually 1-2) and get the first element with a class of foo
  2. Get the next/previous element

Proposed solutions

There are two components to coming up with a solution:

  1. Syntax: How to specify elements relative to the current element (i.e. the one the attribute is specified on)?
  2. Disambiguation: Assuming we don't want to add new attributes for this, how to disambiguate this syntax from the id references currently in use?

1. Disambiguation

In theory IDs can contain any character, though in practice they very rarely contain characters going beyond CSS idents. So how do we come up with a syntax that minimizes conflicts with ids used in the wild? There are two main categories here.

1a. Syntactic switch

This approach allows mixing absolute and relative references even on the same element by using a syntactic switch to say "this is not an id, it's a relative reference".

It would require a fair bit of web compat research to flesh out the details (I can reach out to the HTTP Archive folks), but the main paths here are:

  1. Imposing restrictions on the relative syntax so that it needs to contain certain characters that are very unlikely to appear in IDs, e.g. that the value needs to begin with & or :. Ids can still be specified by escaping these characters.

Example:

<label for="& + *">Foo:</label>
<input name="foo" />
  1. A functional syntax that wraps the relative reference (e.g. selector(), path(), relative(), ref() etc.). This is more verbose, but has the added benefit of clarity and extensibility. If plain names like selector() are not web-compatible, we could go the route of URL fragments and prepend these functions with a certain symbol to further minimize the odds of collision.

Example:

<label for="selector(+ *)">Foo:</label>
<input name="foo" />

1b. Scoping attribute

Instead of a special syntax, this would introduce an additional attribute that switches how references work on an entire subtree.

Ideally, the attribute is not just an opt-in, but also adds value, e.g. by specifying the scope of matching so that references can be simplified. Scopes can be nested, and the parent scope is matched if the closest scope did not yield any results. The syntax of individual attributes need to provide ways to escape the scope, for the use cases where global matching is genuinely desirable.

A big downside of this approach is that because it affects references across a whole subtree, it makes migration more painful, unless we do weird things like "match as an id first, and if that doesn't match anything, try something different", which can be unpredictable and error-prone.

Example:

<li idscope>
	<label for="foo">Foo:</label>
	<input id="foo" />
</li>
<li idscope>
	<label for="foo">Foo:</label>
	<input id="foo" />
</li>

2. Syntax

I see two avenues here:

  1. CSS selectors, potentially with severe restrictions, especially at first.
  2. Identifiers that an already be used on more than one element (e.g. class or name)

An attribute to restrict scope (see 1b) would be useful for both, but while it is a convenience for 1, it is essential for 2 to be useful.

While a custom microsyntax might be tempting, I would advise against it (we even have a TAG principle in the works advising against custom microsyntaxes).

2a. CSS selectors

CSS has recently introduced relative selectors that start with a combinator and/or can use :scope or & to represent the current element (see 1 2).
If relative selectors could be allowed in these attributes, authors could do things like + .description or .description:has(+ &) etc. If the selector specified matches multiple elements, the first one will be used unless the attribute expects multiple elements.

Not the entirety of CSS selectors needs to be allowed.
In fact, I think an MVP could be as small as just <id-selector> | [<combinator>? [ <type-selector> | '*']? <class-selector>* ]+ (see below wrt combinators).
In syntaxes that involve a scoping attribute (see 1b), <id-selector> could still match globally, providing an escape hatch from the scoping.

Pros:

  • Power. CSS selectors are an incredibly powerful querying language and new developments in CSS selectors will automatically make this syntax more powerful as well. Even if only a very restricted subset ships, it would be very easy to progressively enable add CSS selector syntax to the allowlist.
  • Familiarity: CSS selectors are a syntax authors are already familiar with.
  • Potential to solve more than ergonomics: there are many discussions about cross-root ARIA, as well as discussions about re-introducing some form of a Shadow DOM combinator. Something like this could be a piece of that puzzle.

The main downside seems to be performance. Having to specify "the previous element" with a :has(+ &) that searches the entire DOM tree is likely unacceptable. I would need to check with the rest of the CSS WG, but I suspect that if the WHATWG is interested in pursuing this, we might be open to exploring combinators that go backwards (previous sibling, parent) to facilitate common cases without :has(). Things like - for "previous sibling" and < for parent have been proposed before and add value to authors more generally as well. I suspect this would only be tenable if these kinds of backwards combinators are a possibility and/or combined with an attribute to limit scope. (edit: CSS WG issue filed)

2b. Identifiers

Even something as restricted as being able to specify an identifier and a root for the query would address the vast majority of use cases. So basically all we need is a way to express a non-unique identifier and a scoping attribute to mark the root of the matching.

Candidates for this could be:

  • Class names
  • name attribute
  • itemprop attribute
  • property attribute

This produces a very concise, readable syntax for common cases, maintains the same syntax for the individual attributes, and removes the disambiguation problem. However, it is unclear whether a single hierarchy of scopes would be sufficient to cover use cases, and makes it harder to interpret individual values.

There are two strategies here, each with its own tradeoffs.

Only look at non-unique identifiers in subtrees with the scoping attribute

This means authors would have to opt-in to this kind of matching, by using a scoping attribute (e.g. namescope, or even something that specifies the identifier being scoped e.g. refscope="name").

This is more predictable, but makes migration costly. To enable referencing elements globally, the scoping attribute would need to be added to the root element as well, which makes it even harder to mix and match id references with relative references.

Match as id first, fall back to non-unique identifier if no element found with said id

This ensures that copying a chunk of HTML within another does not break, but it means that references can break by simply adding an id in another place in the document, which can be very hard to debug. There is also no precedent in the web platform where the same identifier can mean either id or something else (especially with different scopes!).

3. What if we could fix this without any new syntax?

This is a stretch, but might be worth exploring.
name is an existing attribute that identifies an element similarly to an id, but does not have the restriction of uniqueness.

The algorithm for resolving references could be redefined as:

  1. First, look for an element with that id. If found, return that.
  2. Let scopingRoot = referencing element
  3. While scopingRoot != document
    1. Look for an element with a name equal to the identifier provided inside scopingRoot.
    2. If found, return it.
    3. Otherwise, let scopingRoot = parent of scopingRoot

I wonder how web-compatible something like that would be. Since it would only make a difference if the reference is broken to begin with, maybe it's not too unrealistic?


I’m still unsure what the best solution is, but I’m leaning towards 3 if it's web-compatible, or 1a + 2a if not, perhaps with an optional scoping attribute.

Rationale:

  • Attribute values are self-contained, and can be interpreted by simply looking at the attribute value
  • It maintains the ability to copy-paste fragments of HTML without breakage
  • Allows mixing absolute and relative references, avoiding cliffs

If there is consensus to pursue this, I could do the research of exploring what syntax could be web-compatible.

Activity

  1. changed the title [-]Improve DX of IDREF attributes by allowing relative references instead of only ids[/-] [+]Improve DX of element reference attributes by allowing relative references instead of only ids[/+] on Feb 19, 2024
  2. sashafirsov commented on Feb 19, 2024

    @sashafirsov

    The scope perhaps can be less demanded when the root element for web components become a thing beyond CSS styling. But even with that, the relative selector is highly needed.

    The selectors language perhaps need to be addressed in another proposal. As URL can have the protocol, selectors should as well.
    CSS and XPath are natively supported by most of browser. Others or extensions of base ones would be polifilled.

  3. LeaVerou commented on Feb 19, 2024

    @LeaVerou
    MemberAuthor

    As URL can have the protocol, selectors should as well.

    They already do, as I discuss in the first post. 🙃 The syntax discussion here was about what subset of relative selectors to support, not to define relative selectors.

  4. triskweline commented on Feb 19, 2024

    @triskweline

    I can share some pains, design decisions and experiences we had with relative references over the years. This is from my work with Unpoly, an HTML extension where links update fragments instead of full pages. For this we needed a way to reliably target elements.

    • We use CSS selectors to target fragments. We haven't had a need for something more powerful since :has().
    • We also use a pseudo :origin to refer to the current element (:scope wasn't a thing when we named this).
    • When you show content in overlays ("dialog", "modal"), the risk of references matching the wrong element increases. In Unpoly CSS selectors never match an element in another layer unless the other explicitly allows this with an [up-layer=any] attribute. I feel this is already an issue in HTML since <dialog> was introduced.
    • A sharp edge with <label for="some-id"> is that clicking will blindly focus the first element with that id. Unintuitvely this may match elements in another form, or in another layer. We patch the label / input matching so elements within the same form are preferred.
    • A very common use case is to match within an ancestor of the current element. E.g. the form of an input, or another input within the same form. You can do this explicitly :has() and :origin, e.g. form:has(:origin) .other-input.
    • For convenience we also match ancestor elements preferrably. E.g. form would first look for the closest ancestor form and only then look through the rest of the page. Also form .other-input would first try to find .other-input within the same form, before looking at other forms.

    We have not needed introduce new syntax aside from :origin and :has() (before browser support was there). However, a similiar library htmx uses custom selector synxtax like closest .foo.

  5. jimmyfrasche commented on Feb 19, 2024

    @jimmyfrasche

    This is another area where it makes it hard to reason about server side template partials like I discussed re hN tags in #5033 (comment)

    Another problem with id other than uniqueness is that it does way too much.

    I would like something like this sketch:

    A refscope tag (or maybe it's an attribute) defines a new scope. :root implicitly defines a root scope.

    Elements have a ref attr to use instead of id. Unlike id it only defines a name and that name is local to the current scope. (If there are multiple identically named refs, then which one wins should be defined in the standard and browsers should print a warning in the debug console.)

    If something is referred to by name, the refs in the current scope are searched first. If there's no match, check the parent scope; repeating as necessary until reaching the root scope. If there's no match after all that, check for a matching id.

    A tag could have both a ref and id and that may be confusing and certainly not recommended but everything works out.

  6. dginev commented on Feb 19, 2024

    @dginev

    The MathML 4 effort has some overlapping interest in improved DX for referencing. Exactly due to the difficulties of managing global ids, we have tentatively introduced a new arg attribute to anchor referencing in MathML Intent, targeting the feature of accessible navigation of math expressions:
    https://w3c.github.io/mathml/spec.html#intent_reference

    Simple example:

    <msup intent="power($base,$exp)">
      <mi arg="base">x</mi>
      <mi arg="exp">n</mi>
    </msup>

    We have had the constraint of keeping the traversal algorithm as simple as possible, which has so far kept us from introducing relative selectors (sibling, ancestor). Nevertheless, MathML has viable use cases where relative selectors are quite natural, such as accessible walks through tabular diagrams (realized via <mtable>).

    The traversal algorithm for intent/arg referencing is scoped to the current subtree (references can only point to descendant nodes). It also has an additional stopping condition at nodes carrying the intent or arg attributes, to allow stacking of multiple math notations.

    As we have multi-format content (such as scientific diagrams via SVG+MathML, as well as block equations mixed with text), it would be a significant boost to DX if we could share a uniform referencing scheme.

  7. sorvell commented on Mar 1, 2024

    @sorvell

    Feedback

    @LeaVerou

    Many HTML attributes need to reference one or more HTML elements in the document

    It may be worth distinguishing the problems describing 1-to-1 relationships with those describing 1-to-N. For example, ids are not used for <input type="radio"> but are, unfortunately, required for things like aria-controls.

    Potential to solve more than ergonomics

    I suggest this be promoted to a core goal of the proposal. This is a bit spicy but arguably the current lack of a way to associate elements across scopes violates platform design principles.

    Being able to link to elements in a way that is relative to the element the attribute is specified on would solve all of these issues, and make writing ARIA much more pleasant.

    I think the problem isn't clearly enough defined to determine if this is true. In particular, the id based system is independent of document structure, and most of the ideas here for a relative system depend on it. That just seems like a trade off that may be better or worse for the various different use cases.

    Proposed solutions

    The various options here are a little hard to understand. It'd be great to add some illustrating examples.

    @jimmyfrasche

    Another problem with id other than uniqueness is that it does way too much.

    Totally agree, and this may even be the core problem to solve.

    Thinking Aloud...

    • Naming things is hard, but uniquely naming things can be really problematic since it requires global knowledge. Where this isn't necessary, it shouldn't be required. This is already the case for <input type="radio" name="a"> since these are form scoped.
    • If the tree is used for scoping, explicitly using a scoping element may be worth it for clarity.
    • There are currently often special attributes for one side of the equation only, e.g. for, popovertarget, invokertarget. Perhaps the other side should have them as well: e.g. popoverid, etc.
    • Shadow DOM is an existing DOM scoping mechanism, can it be used as part of the solution here? If not, what abilities might it need to gain to be useful for this?
    • At least for loose relationships that aren't exclusive, not claiming a general attribute value like id or name is valuable since it makes the naming easier, e.g. refs="popoverA invokerB"
  8. LeaVerou commented on Mar 8, 2024

    @LeaVerou
    MemberAuthor

    I just added another proposed idea to the first post:

    3. What if we could fix this without any new syntax?

    This is a stretch, but might be worth exploring.
    name is an existing attribute that identifies an element similarly to an id, but does not have the restriction of uniqueness.

    The algorithm for resolving references could be redefined as:

    1. First, look for an element with that id. If found, return that.
    2. Let scopingRoot = referencing element
    3. While scopingRoot != document
    4. Look for an element with a name equal to the identifier provided inside scopingRoot.
    5. If found, return it.
    6. Otherwise, let scopingRoot = parent of scopingRoot

    I wonder how web-compatible something like that would be. Since it would only make a difference if the reference is broken to begin with, maybe it's not too unrealistic?


    Thanks for the thoughtful response @sorvell. Some replies:

    Many HTML attributes need to reference one or more HTML elements in the document

    It may be worth distinguishing the problems describing 1-to-1 relationships with those describing 1-to-N. For example, ids are not used for <input type="radio"> but are, unfortunately, required for things like aria-controls.

    Interesting. What do you think are the differences?

    Potential to solve more than ergonomics

    I suggest this be promoted to a core goal of the proposal. This is a bit spicy but arguably the current lack of a way to associate elements across scopes violates platform design principles.

    As an editor of the document you are referencing, I have no idea how that principle relates to this problem. 😁
    That said, I'd be fine with making that a core goal of the proposal, though I'm not sure how that will materially affect the odds of it moving forwards.

    Being able to link to elements in a way that is relative to the element the attribute is specified on would solve all of these issues, and make writing ARIA much more pleasant.

    I think the problem isn't clearly enough defined to determine if this is true. In particular, the id based system is independent of document structure, and most of the ideas here for a relative system depend on it. That just seems like a trade off that may be better or worse for the various different use cases.

    Why is it a goal to have a referencing system that is independent of document structure? Document structure is not created in a vacuum, it typically reflects hierarchical relationships (and when it doesn't, that's a failing of some web platform technology — e.g. when authors have to put elements directly inside <body> to make sure they're on top).

    Also, the id-based system is not going away. That wouldn't be web compatible. Any relative referencing system is in addition to it.

    Proposed solutions

    The various options here are a little hard to understand. It'd be great to add some illustrating examples.

    Agreed. I added a few examples, does this help? I could add more if you point me to specific sections that are still unclear.

    • Naming things is hard, but uniquely naming things can be really problematic since it requires global knowledge.

    +1000

    Where this isn't necessary, it shouldn't be required. This is already the case for <input type="radio" name="a"> since these are form scoped.

    • There are currently often special attributes for one side of the equation only, e.g. for, popovertarget, invokertarget. Perhaps the other side should have them as well: e.g. popoverid, etc.

    Naming things is hard so let's add more naming tasks? 😁
    What are some use cases where you may want to have a different name for e.g. popover use cases and a different one for e.g. forms?

    • If the tree is used for scoping, explicitly using a scoping element may be worth it for clarity.

    Unless any ancestor container could potentially be the scope, and proximity determines where to look, see new option 3.

    • Shadow DOM is an existing DOM scoping mechanism, can it be used as part of the solution here? If not, what abilities might it need to gain to be useful for this?

    Shadow DOM is a very heavyweight scoping mechanism that does too much. Nobody would switch to Shadow DOM simply to use relative references, as the friction involved in that far, far outweighs the friction of assigning unique ids.

  9. mayank99 commented on Jul 4, 2024

    @mayank99

    A potential 4th (or 2c) option that might play nicely with HTML modules, DOM parts, and template instantiation: "Automatic generation of unique ids in each instance of the template".

    Consider this template that uses the declarative DOM parts syntax (which might change):

    <template>
      <label for="{{ uid(fruit) }}">Fruit</label>
      <input id="{{ uid(fruit) }}" />
    </template>

    Here, uid() is like a built-in function that's available for use within DOM parts. It takes an optional key that is scoped to the template, and returns an IDREF that is guaranteed to be globally unique.

    When instantiated, this template would produce something like:

    <!-- First instance -->
    <label for="fruit001">Fruit</label>
    <input id="fruit001" />
    
    <!-- Second instance -->
    <label for="fruit002">Fruit</label>
    <input id="fruit002" />

    The optional key is only useful when you need to actually associate it with another element. It can be omitted when there's a simple need for a unique IDREF.

    <template>
      <div role="option" id="{{ uid() }}">{{ }}</div>
    </template>
    
    <!-- instantiated N times -->
    <div role="option" id="__001">Option 1</div>
    <div role="option" id="__002">Option 2</div>
    <div role="option" id="__003">Option 3</div>

    This probably wouldn't solve all cases, but I just wanted to put it out there. To me, it feels more flexible than something like idscope because it's explicitly opt-in (meaning you can still use global ids in the same template). It is new syntax, but we'll need that new syntax for DOM parts anyway.

  10. dbaron commented on Sep 5, 2024

    @dbaron
    Member

    So while XPath hasn't gotten much interest lately, it's possible that it might be a good fit for this sort of thing.

    The reasons I think XPath may be worth considering here are:

    1. XPath already has solid syntax for relative paths starting from somewhere in the middle of a tree
    2. I think CSS selectors and XPath are optimized for slightly different problems:
      • CSS selectors were optimized for the problem of "given one element, find all the selectors that match"
      • XPath was optimized for the problem of "given an XPath expression, find all the elements that match"

    It's perhaps questionable whether it falls into the "another microsyntax" trap: it's already a part of the Web (see e.g. domxpath and dom/xslt tests), but most of the things that use it are not widely used today. There's definitely a learning curve for those who don't know it -- but it's also pretty powerful and likely to do a pretty large subset of the things people would want from a feature like this.

    [Edited to add] A big caveat that would need some research is that I'm not sure how well the existing implementations work with HTML (rather than XML).

  11. sashafirsov commented on Sep 5, 2024

    @sashafirsov

    +1 @dbaron
    XPath is acually part of browser DOM implementation via document.evaluate method. Which makes in a native feature to be extended to HTML attribute as in this proposal.
    There is a DCE (Declarative Custom Element) implementation which is using XPath for such kind of relations.

    Even if the attribute can refer either ID, or css, the URI convention with schema as xpath: preffix will fit there well.

  12. Delapouite commented on Sep 5, 2024

    @Delapouite

    Talking about XPath, a few years back @WebReflection attempted to get the ball rolling around upgrading the spec: whatwg/dom#903

  13. WebReflection commented on Sep 5, 2024

    @WebReflection
    Contributor

    if there's anything I could add to that old attempt to refresh XPath on the Web:

    • we proposed XPath selectors within CSS and that was nuked
    • we stated that at least :has(...) selector would've been great and we (at that time) collaborated with Igalia to bring :has(...) selector in ... :has(...) selector is wonderful and yet half powerful as XPath in CSS would've been
    • there are dozens, if not hundreds, of people using XPath to create filters in the Ads blocking field ... stating it's "not interesting" is actually a bit too much of a stretch when everyone dealing with more complex selectors well understand and know that's the Web tech stack to use for anything more complex than just visual representation of an element
    • I still would love to see matches and replaces in current implementation or a switch to at least v2 version of the specs but I am not 100% sure that would solve this specific case
    • I still believe the reason "nobody" uses XPath these days is because they know it's an abandoned legacy thing on the platform ... I don't understand why WebSQL couldn't have done the same end (being supported with no updates on the underlying sqlite version guaranteed) but I am sure XPath is a standard that, if ever removed, will break badly a lot of things in the wild

    That being said, when it's @LeaVerou suggesting DX improvements, I am usually 100% in favor of that so I won't bother this thread anymore with some hope that some solution would land in a way or another 👋

  14. 110 remaining items

  15. bramus commented on Aug 20, 2025

    @bramus

    not sure if this has already been mentioned, but ... one approach i'd love to see is being able to get a reference to an object in JavaScript, and use that to then define a relationship programmatically. as in: instead of just going by IDREFs, being able to make object references. (how i'd then get the object reference would be open to whatever approach i choose to take ... which could well include things like query selectors etc)

    #11577 was filed for that just yesterday :)

  16. bahrus commented on Aug 20, 2025

    @bahrus

    Unpopular suggestion of the day, perhaps what @mayank99 was suggesting:

    <form generatedids="foo,bar">
    ...
    <label for={{foo}}>foo:</label>
    ...
    <input type=checkbox id={{foo}}>
    
    ...
    
    <label for={{bar}}>bar:</label>
    ...
    <input type=checkbox id={{bar}}>
    
    </form>

    The platform would guarantee that the auto generated ids are unique within the ShadowDOM realm (including outside any ShadowDOM). Replacement would happen during parsing. This would make the connection "latch" at start up, and allow for moving things around the realm with no breakage.

    If an outer tag that contains the form element also has generatedids = "foo", the inner most one trumps, similar to nested const's in JavaScript

    What use cases does this miss?

  17. mayank99 commented on Aug 20, 2025

    @mayank99

    @bahrus My suggestion was similar but not quite the same. The key differences are:

    • It should be necessarily tied to "template instantiation". My understanding is that the declarative DOM parts syntax only applies to <template>.
    • I'm not sure what you mean by "within the ShadowDOM realm", but there should be no shadow DOM involved. Once the template is instantiated, the IDs should be transformed into something globally unique.
    • There shouldn't be a need for a generatedids attribute, but if it's unavoidable then it must go on the <template> element, rather than <form>.

    I see you've opened #11585. I'll leave some more thoughts over there.

  18. alice commented on Aug 21, 2025

    @alice
    Contributor

    I finally got around to collating the responses I got to my questions about IDREFs: https://notes.igalia.com/XlsPwU5sQfuaWYHwhtBMtA

  19. jyasskin commented on Aug 25, 2025

    @jyasskin
    Member

    Leaving a breadcrumb to a piece of prior art, CSS has been using names to establish cross-links between elements. Each purpose can assign its own names (e.g. scroll-timeline-name vs anchor-name), and names can be explicitly scoped to a component (e.g. anchor-scope).

  20. sashafirsov commented on Aug 26, 2025

    @sashafirsov

    Unpopular suggestion of the day, perhaps what @mayank99 was suggesting:

    ... foo: ...

    ...

    bar:
    ...

    The platform would guarantee that the auto generated ids are unique within the ShadowDOM realm (including outside any ShadowDOM). Replacement would happen during parsing. This would make the connection "latch" at start up, and allow for moving things around the realm with no breakage.

    This feature belong to templating and already exist in XSLT. The need of fully functional template is out of scope of relative reference discussion here as the subject is not rendering but existing DOM relations.

  21. bahrus commented on Aug 26, 2025

    @bahrus

    This feature belong to templating and already exist in XSLT. The need of fully functional template is out of scope of relative reference discussion here as the subject is not rendering but existing DOM relations.

    The name I used happens to be inspired by the name used in xslt, and yes, I think you can define a variable in xslt and refer to it with multiple elements. I did make a separate proposal, because I agree it is different from this one. I was very much in favor of this proposal, but I think at least 80% of its appeal, to me, stemmed simply from the platform not making working with id's ergonomic, which the other proposal tries to do. Id's have a kind of well-deserved stigma, which I'm trying to overcome when I imagine a world in which the other proposal is implemented. I still do think there might be scenarios where semantically it would make more sense to refer to other elements by some other attribute, or even by tag name. Maybe the command linkage is one such scenario, not sure. It looks like a "specifier" attribute is being seriously considered as far as linking imports. And of course if the platform doesn't implement something like 11585, then the id stigma remains justified, and the appeal of this proposal remains much stronger in my mind.

    Hopefully my alternative / supplementary proposal makes clear that it does not require the use of the template element, or any other templating element, just HTML, so it doesn't "belong" to templating, but rather is a segue into SSR compatible templating, I hope. But the proposal stands on its own, even if it isn't followed up by SSR/isomorphic compatible templating.

  22. LeaVerou commented on Aug 26, 2025

    @LeaVerou
    MemberAuthor

    Lots of things to respond to in this thread, but taking @jyasskin's advice, @noamr and I started an explainer here.

    Still very much a work in progress, but we're posting it here to invite collaboration, so we can have a single source of truth, as currently this thread has grown to a length that is unmanageable even for folks who have followed it from the start.

  23. keithamus commented on Sep 8, 2025

    @keithamus
    Member

    Some early thoughts. I haven't digested the whole thread so forgive me if I'm retreading old ground:

    • I worry adding more syntax for IDs doesn't substantially solve the problem. Writing a selector to target a single element is no more or less burdensome for the developer, in abstract they still need to produce a significantly unique string which seems to be part of the challenge. It also means mechanisms by which a developer can select for these in CSS become convoluted (e.g. would CSS like label[for=my-input] become label[for="& .* input"]?).
    • Adding an attribute (such as idscope) seems straight forward for elements looking at other IDs but there becomes some amount of issues that unfold from this, for example existing APIs such as document.getElementById() presumably remain untouched (they find the first ID matching in the tree). Again we have an issue with CSS selectors but it is less of an issue, but this means there is a second order effect that as developers use more scoped IDs the duplication of said IDs proliferates, which causes the global lookups to be less and less useful over time. This may contribute to user harm, because it means that fragment IDs in URLs may become less stable. While we have text fragments these can be even less stable than fragment IDs for certain pages (e.g. a page with dynamic content, like a comment thread).
  24. WebReflection commented on Sep 8, 2025

    @WebReflection
    Contributor

    @keithamus

    Writing a selector to target a single element is no more or less burdensome for the developer

    assuming the content of any container could easily change accordingly with circumstances, writing a top-container id followed by its target as plain CSS would make things way easier than needing unique identifiers all over the place, plus let's keep in mind every single ID leaks on the global context as property and there is no API to guarantee a new DOM identifier neither out there, neither for JS nor for Server Side languages.

    which causes the global lookups to be less and less useful over time

    I am honestly curious to understand when that global (leak?) lookup is really that useful except for demo pages where the amount of IDs is minimal and it's just "handy" but not elegant, neither robust (discrepancy between a cached expectations and what the next getElementById could return instead).

    Mind sharing an example of such usefulness? Thanks!

  25. keithamus commented on Sep 8, 2025

    @keithamus
    Member

    I am honestly curious to understand when that global (leak?) lookup is really that useful except

    Perhaps not so much for developers, but for users it certainly is, as the ID can be used in a URL hash. The risk with introducing scoping is that developers are less inclined to use it in a way that users can leverage via the URL hash.

  26. WebReflection commented on Sep 8, 2025

    @WebReflection
    Contributor

    @keithamus but I feel like that's exactly what's being tackled in here: ids matter, they do on the URL, they do on the global context pollution, they do for assistive technologies ... the current state is that ids don't matter anymore because to automate accessibility IDs are trashed all over the place without any meaning whatsoever, just to satisfy labelled-by requirements, right?

    So I fully agree with you there that IDs are relevant, but latest 20 years of Web growth rather showed how these are either a limitation, when meanings matters too, or an abused legacy feature automated to satisfy requirements, which is (imho) a bigger bummer to deal with.

    edit on that note, a URL that points at a label without any context attached doesn't look like the best the Web can offer neither, but that ship has sealed long time ago

  27. added
    a11y-trackerGroup bringing to attention of a11y, or tracked by the a11y Group but not needing response.
    on Sep 12, 2025
  28. oscarotero commented on Nov 5, 2025

    @oscarotero

    I'd like to propose a scope-based solution with relative and absolute ids:

    <div idscope="field-name">
      <label for=".input">Name</label>
      <input type="text" id=".input">
    </div>
    
    <div idscope="field-email">
      <label for=".input">Email</label>
      <input type="email" id=".input">
    </div>

    The idscope attribute creates a new scope. It means all inner ids starting with dot . are relative to this scope (it's similar to relative paths in the filesystem). For example, the .input id is resolved to field-name.input (in the first scope) and field-email.input (in the second scope). The dot is just an idea, we can use a different character to indicate that an id is relative to the current scope.

    This method allows to use a reference to an id outside the current scope, which is compatible with URL hashes (just use the full path, ie #field-name.input).

    The scopes can be nested:

    <form idscope="form-login">
      <div idscope="field-name">
        <label for=".input">Name</label>
        <input type="text" id=".input">
      </div>
      
      <div idscope="field-email">
        <label for=".input">Email</label>
        <input type="email" id=".input">
      </div>
    </form>

    Now, the resolved id is, for example form-login.field-name.input (note that the values of idscope don't need to start with a dot, because they are always relative to the current scope if exists).

  29. noamr commented on Nov 17, 2025

    @noamr
    Contributor

    Note that conversation on this issue continues in https://github.com/wicg/idrefs.
    It's a broader conversation about a topic, rather than specifically on using selectors as the a solution for this, which is a discussion which can use some rest :)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    a11y-trackerGroup bringing to attention of a11y, or tracked by the a11y Group but not needing response.addition/proposalNew features or enhancementsneeds implementer interestMoving the issue forward requires implementers to express interest

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions