Leaving slide mode.

Fixing HTML element references (IDREFs) on the Web

Matthew Tylee Atkinson, Alice Boxhall, Lea Verou, Sarah Higley, Noam Rosenthal, Jeffrey Yasskin

TPAC 2025
Kobe, Japan & online
10–14 November 2025

Important info

Ground rules

Goals for this session

To find areas of consensus regarding

Non-goals

Agenda

Gaps

Issues list of the TAG's web platform gaps repo
https://github.com/w3ctag/gaps/issues

Please file issues on the repo to talk about gaps you've noticed!

IDREFs gap

IDREFs issue in the TAG's web platform gaps repo
https://github.com/w3ctag/gaps/issues/2

What (if anything) needs fixing?

Themes from developer feedback so far:

Themes from developer feedback so far:

Themes from developer feedback so far:

General concerns

DX

  • Reducing the pain points.
    • Identifying the right pain points.
  • Preserve developer flexibility.

UX/Accessibility

  • Implementation and maintainance burden.
  • Performance hit.
  • Fragility of approach.

Prior art: Unique ID generation

React useId()

export default function FormComponent() {
  const inputId = useId();

  return (
    <form>
      <label htmlFor={inputId}>Name:</label>
      <input id={inputId} type="text" />
    </form>
  );
}

React useId()

The code on the previous slide my result in HTML something like this:

<form>
  <label for=":r1:">Enter your name:</label>
  <input id=":r1:" type="text">
</form>
    

Prior art: ID prefixing

ID prefixing using React useId()

export default function FormComponent() {
  const prefix = useId();
  return (
    <form>
      <label htmlFor={prefix + '-first'}>First name:</label>
      <input id={prefix + '-first'} type="text" /><br />
      <label htmlFor={prefix + '-last'}>Last name:</label>
      <input id={prefix + '-last'} type="text" />
    </form>
  );
}

Prior art: ID prefixing

posthtml-rename-id

Input

<style>
  .selector {
    fill: url(#myId);
  }
</style>

<div id="myId"></div>
<a href="#myId"></a>

Output

<style>
  .selector {
    fill: url(#prefix_myId);
  }
</style>

<div id="prefix_myId"></div>
<a href="#prefix_myId"></a>

Prior art: Scoped ID rewriting

AlpineJS x-id and $id

<div x-id="['input']">
  <label :for="$id('input')">  <!-- ➡ "input-1" -->
  <input :id="$id('input')">   <!-- ➡ "input-1" -->
</div>

<div x-id="['input']">
  <label :for="$id('input')">  <!-- ➡ "input-2" -->
  <input :id="$id('input')">   <!-- ➡ "input-2" -->
</div>

Prior art: Using selectors to refer to elements

htmx hx-target

<!-- A button that causes response-div to be updated -->
<button hx-post="/register"
  hx-target="#response-div" hx-swap="beforeend">
  Register!
</button>
<div id="response-div"></div>

htmx hx-target

<!-- A link that updates itself when clicked -->
<a hx-post="/new-link" hx-target="this"
  hx-swap="outerHTML">
  New link
</a>

Some questions…

(Just possibilities for the discussion, or to stimulate the queue.)

What are the pain points?

Is the problem generation of IDs, or communication accross component boundaries of the IDs?

What other approaches have been used in libraries or tooling?

What are the (UA, AT) development costs?

Could devtools or offline tooling be improved to help the problem?

What are the performance costs?

How would any particular change benefit users?

What other constraints would you want on the potential solution space?

Research

We need to do research to identify the problems. That starts with you!

How can we ensure that the reseach is effective?

Can you help?

Themes from developer feedback were given above; more can be found as an appendix within this slide deck.

Discussion time!

Some points to consider…

Ground rules

Thank you!

Next steps? Check out https://github.com/WICG/idrefs

Reference info

Appendix: Quotes from developers

Theme: repeated content

Theme: unique ID generation

Theme: unique ID generation

Sub-theme: stable IDs

Theme: label/input

Theme: label/input

Sub-theme: label/input wrapping

Theme: SVG

Theme: unique ID generation

Sub-theme: getting generated IDs to both ends of a pair

Theme: JS/toolchain requirement