W3C

– DRAFT –
(MEETING TITLE)

11 November 2025

Attendees

Present
alisonmaher, Ananya, cwilso, frehner, kizu, masonf, noamr, tantek
Regrets
-
Chair
-
Scribe
foolip, zcorpan, ntim, fantasai, noamr4, cwilso, anne, emilio

Meeting minutes

<astearns> what is the doc where scribing is happening?

<tantek> https://docs.google.com/document/d/1XQLLjETtdBPv-xGiGPRALR4X7hgSb_Lk13bdBucEJ_g/edit?tab=t.0#heading=h.51akrqmzup50

leo: presenting slideas

leo: the proposal is a new FormControlRange, extending AbstractRange

leo: FormControlRange is live and automatically updates, like how Range tracks changes

leo: this is inspired by Keith Cirkel's Richer Text Fields proposal

leo: it's different enough from Range to justify creating a new type

leo: would like to get your thoughts on this

leo: there are restrictions on the start/end point that are hard to enforce with the Range API

leo: if we did use Range, maybe we could add a parameter to all methods, but that seems messy

leo: that's the context

rniwa: Range.selectNodeContents() isn't on AbstractRange I think

anne: if use Range directly we have a bunch of problems like this

leo: what we're proposing is this (presenting Example 1)

rniwa: should the Selection API be updated?

leo: it would be live

leo: but would getSelection() getters return these new objects?

leo: I would say yes, return this new FormControlRange

smaug: I'm not sure we want to change what those things return

emilio: is that interoperable right now?

smaug: no, there are differences

rniwa: there may be some compatibility issues then, needs to be discussed in conjunction with the Selection API

smaug: I thought this was more about the Highlight API

leo: custom highlight, yes

rniwa: calling it custom highlights and not interacting with selection is an option

anne: we could also have that be an opt-in

emilio: something added to getRangeAt()

anne: or flip a bit on the Selection object

zcorpan: or a new method

smaug: something something Shadow DOM

rniwa: form-associated custom elements wouldn't be able to work with this API

leo: how can we overcome that?

rniwa: need to make it more generic so that custom elements can use this

rniwa: maybe it wouldn't be called FormControlRange

leo: do we have consensus that a new interface is needed?

rniwa: my concern is a brand new API that doesn't work with custom elements, but if we make it work that would be OK.

emilio: one more option is something that operates directly on a single text node, these controls effectively operate on a string.

emilio: that could also work with contenteditable=plaintext-only

emilio: this new Range isn't very special, except that you don't have access to the string it's pointing into

anne: StringRange, TextRange?

emilio: yes.

anne: maybe set the range through ElementInternals?

rniwa: ideally we want to be able to map the selection from within the shadow root dynamically

rniwa: if it's a calendar widget you want a selection in date/month/year separately, so it's not necessarily a 1:1 map.

smaug: but this is only for text inputs

emilio: it feels like a regular range that operates on a text node.

emilio: maybe 3 different text ranges for date/month/year in that case, and the custom element exposes all 3?

emilio: maybe it's also useful for cases where you do have access to the underlying node

schenney: the issue links to Keith's doc with a bunch of use cases for this

https://open-ui.org/components/richer-text-fields.explainer/

leo: our original intention was to start with just text and be open to custom elements in the future

smaug: there is a risk that we'd have to introduce another range type

anne: it depends on whether custom elements just need parity with built-in elements or need to do more than that

rniwa: we probably don't want to expose the Text node itself

anne: no

emilio: how about PlainTextRange?

<LeoL> https://open-ui.org/components/richer-text-fields.explainer/

emilio: we could easily create a constructor to create a PlainTextRange from a Text node?

emilio: I'm not sure why input and textarea can't just have a getter returning the live range for the current selection? why a constructor?

smaug: because there can be multiple ones for highlighting

rniwa: regular ranges have a clone() method

rniwa: but it would be awkward to create new ranges with offsets, need to clone and edit

leo: we're trying to align with the current APIs

cwilso, can you encourage usage of the queue?

<emilio> To be clear, what I'm proposing, something like: `TextRange HTMLTextAreaElement.getTextRange(unsigned start, unsigned end);`

rniwa: my question is if we have an interface with a constructor taking a host and two numbers, that only works for text field-like custom elements

rniwa: is there an alterantive where it would work with multiple editable regions?

<emilio> And then custom elements could do something like `new TextRange(); textRange.setTextRange(myMonthNode, 0, 2); return textRange;` or so

rniwa: ideally we'd have one solution that would work for multiple use cases

leo: you're saying it doesn't work because it doesn't work with multiple ranges?

rniwa: maybe we could add a name that specifies which selectable area it refers to

emilio: I pasted the example above of what I mean

emilio: as long as we don't expose the actual Text node in the interface I think it would work on both inputs and custom elements

rniwa: that might be a good design

rniwa: one thing to consider is a calendar widget is some way to "forward"... but maybe it's OK

anne: then the other properties can't expose the boundary points, because they'd be in the shadow tree

anne: not sure what abstract range currently does

emilio: that would be important

rniwa: we could also return a host

zcorpan: makes more sense than returning <body> which is what Range does :)

zcorpan: maybe the constructor needs to have a parameter for the host?

emilio: the other alterantive would be to just return the text node, but that exposes it from the text node

anne: we can't do that

zcorpan: return the text node data?

[scribe is having difficulties scribing back and forth]

cwilso: we are at time!

leo: are we closer to a solution?

anne: I think we need a design for the form-associated case, but it doesn't need to be included in v0

anne: we have some alterantives

rniwa: I think we can come up with something

[general rejoicing and optimism in the room]

leo: we'll go back and have a look

anne: I'm happy to help

AsyncContext

andreubotella: Proposal tc39/proposa-async-context

andreubotella: trying to figure out integration between tc39 and whatwg

<Jxck> tc39/proposal-async-context

andreubotella: Open question how the stages processes map to each other

andreubotella: What AsyncContext does, it propagates... has AsyncContext.Variable class

andreubotella: run() method

andreubotella: showing await example

andreubotella: gets propagated through await

andreubotella: set a new value in the stack

andreubotella: setTimeout example

andreubotella: asyncVar.get() returns same value from setTimeout() in run() as sync in run()

andreubotella: useful to keep track of state across disconnected parts of an application, calling to other third-party code

andreubotella: which async operation they are in

andreubotella: which async branch

andreubotella: parallel to localStorage

andreubotella: used to instrument ThreadLocalStorage in C++, not to the web localStorage

<nicolo-ribaudo> For the minutes: the parallel was to ThreadLocalStorage in C++, not to the web localStorage

andreubotella: would allow authors to instrument their applications, would be more performant for users

andreubotella: trying to see if this works as an explainer for the whatwg stages process

nicolo-ribaudo: tc39 want to be formal about stages

nicolo-ribaudo: suggest being loose on whatwg side

nicolo-ribaudo: advance roughly at the same time

andreubotella: for stage 3 it signals that it's ready for implementation, should be in sync

andreubotella: tc39 might advance to stage 3 at the time whatwg advances

andreubotella: whatwg stage 3 could signal tc39 stage 2.7

<Zakim> nicolo-ribaudo, you wanted to ask if we have stage 1

nicolo-ribaudo: requesting whatwg stage 1

nicolo-ribaudo: believe the proposal fulfills the requirements

cwilso: in general, bring it to the triage meeting, group can object or agree

rniwa: what happens with multiple values

andreubotella: have single map to a value

andreubotella: if you use immutable map, do await or setTimeout, store reference

andreubotella: multiple values are variable

anne: can you use multiple Variables?

andreubotella: yes

jridgewell: restored after await

andreubotella: single asynccontext are variable. Have internal map, not user exposed

<nicolo-ribaudo> (name of the person who spoke is jridgewell, for the minutes)

andreubotella: better if it's mutable

anne: better if you didn't explain in terms of impl

anne: explain what web dev can observe

rniwa: want to have multiple values, return some unique value, map to some value at that moment

nicolo-ribaudo: map is internal impl detail

nicolo-ribaudo: multiple variables, multiple keys

nicolo-ribaudo: set them one by one

mmocny: Similar to normal valiables

smaug: status, i think stage 1 is fine

smaug: hoping webkit folks would review, from integration with web apis POV, and memory management

nicolo-ribaudo: do you think we can go through the current document

nicolo-ribaudo: setTimeout has an obvious answer

smaug: need to go through all apis

nicolo-ribaudo: would be good to have participation from all browser engines

anne: should there be something for AbortSignals?

nicolo-ribaudo: just an event?

anne: yes

andreubotella: events are most complicated part

andreubotella: work different in different situations

andreubotella: events are sync, (missed),

andreubotella: loadend event

andreubotella: there are many of those events, if we decide to propagate those, from the same agent and same origin it's propagated

<jridgewell> s/(misssed),/browser originated events have no obvious context to propagate, like `onload`

andreubotella: maybe not expected by developers

andreubotella: observers, not fully figured out

andreubotella: to be discussed during stage 1

andreubotella: maybe can simplify if it's too complicated

andreubotella: a lot of web apis that do async things

domfarolino: the notes says, propagating .... same result as ...

domfarolino: idea is, the snapshot is taken after callback is run

domfarolino: can snapshot happen different time?

domfarolino: ran callback ...

nicolo-ribaudo: difficult to do from different context

domfarolino: do something after callback has run

domfarolino: is it possible to get disconnected from scheduler api

nicolo-ribaudo: if you postmessage a worker

domfarolino: how would this work with observables

domfarolino: create an observable in callback

domfarolino: later on, run subscribe

domfarolino: what is the value of Variable?

domfarolino: overridden by run?

nicolo-ribaudo: when you call next() it propagates

domfarolino: wondering if there's something that makes sense

domfarolino: not obvious what the right behavior is

smaug: general issue

domfarolino: some apis are tricky

snek: precise semantics how asynccontext works

<rniwa> q>

snek: any ambiguities, documentation about what we want to happen

domfarolino: it is what we define for each api

snek: if observable is going through a web api, but in other cases can define from first principles for the api

<Zakim> cwilso, you wanted to break

jridgewell: similar issue already for observer-type apis

OpenUI/WHATWG issues

<ntim> where is the agenda

fantasai: These issues are all related, mainly about anchor positioning. Affordances useful for accessibility
… create a connection with popover API for accessibility, also with anchor positioning for presentation

fantasai: what about non popovers? how to express those relationships

(popovers use popovertarget)

domfarolino: IIUC, do we need markup to associate non-popover to its anchor?

fantasai: ARIA has a lot of mental load. Anchor positioning has both presentational use cases where the bindings shouldn't be expressed, and has cases like popover where the link needs to be expressed in the a11y tree. There are going to be cases where the semantic relationship needs to be expressed, but it is not a popover. What is the markup for those?

<tantek> +1 fantasai. making the anchoring relationship more explicit in markup with a more memorable attribute (for both popover and non-popover), rather than re-using ARIA, is a more developer-ergonomic approach.

kizu: What are the use cases? tooltips, common use case is where side notes where you position notes on the left of the content. There are many potential use cases where the content is always visible, and does not pop over. You want to put notes that is displayed along side the main content. On mobile, you could use display: none to make them popover, but if you display them as side notes, keyboard order is not going to be the same.

kizu: So if we had this mapping, it would be useful

kizu: two ideas: still use popover, removing the default style of display: none, e.g. making it visible, but not a popover by default.

we need to think about aria/keyboard order

second idea: allow making a popover open by default, but semantically different from just an in-flow element.

How do we handle an use case like side notes ?

anne: I like the use cases

anne: it doesn't work if you have multiple notes for one content

kizu: anchor positioning can do this with min/max calculations

<tantek> +1 anne. multiple footnotes for the same content / point in the text (I've had examples of this in my blog, and this is common in Wikipedia too)

kizu: one issue is the bottom of the doc, where overlapping can happen

fantasai: point is, we have a layout mechanism but not markup support for it

<TabAtkins> `.sidenote { anchor-name: --sidenode; top: max(anchor(--note1 top), calc(1em + anchor(--sidenote bottom))); }`

<TabAtkins> ^^^ Sit next to the anchor, or below any preceding sidenotes.

anne: using popover seems a bit wrong, i could imagine the aria mapping could get jarring for assistive tools

domfarolino: you probably don't want the top layer stuff

fantasai: you might want to introduce something else than popover, but what would that be

<fantasai> whatwg/html#9144

fantasai: there's an existing PR for the anchor attribute but only does rendering bindings

<tantek> +1 anne. being able to go from the ref to the footnote to the footnote and back to the ref. this is a common Wikipedia use-case.

anne: maybe it should impact focus, in addition to layout. The other thing you want for footnotes is going back to the content.

fantasai: There's two types of navigations if you have footnotes, you might want to navigate and skip through the notes, or you want to see the footnote now.

domfarolino: could we do something that expands the anchor attribute to handle focus stuff?

anne: needs more thought

<anne> See WICG/html-in-canvas for details

<anne> [foolip is going over the details]

foolip: Text is a complex problem. People currently have to ship HarfBuzz to render text properly on canvas

foolip: it's hard to make accessible

[foolip loads a demo]

foolip: Chrome Canary, you can test this

foolip: What I'm showing here is a bunch of form controls rendered into a <canvas>. It looks just like if it was rendered outside the canvas.

foolip: The markup is just all the form controls wrapped in a <canvas>

foolip: And we call JS context.drawElement(...)

foolip: And I can interact with the element, edit the text, interact with the form controls, etc. because the hit testing is wired up to make it work

foolip: Here's a more complicated example, obvious it's not just HTML

foolip: We're seeing some text rotated 30deg. It has alink, Arabic, vertical Chinese, an nline image, svg, emojis, etc.

foolip: Source is just a <div> with all the text, svg, etc. marked up all inside a <canvas>

foolip: As you can see, hyperlinks work. You can right-click and save the wolf image here. Everything Just Works!

foolip: here's another demo. Two cards, one on the left, one on the right.

foolip: In between the cards I've painted a circle. You can mix canvas content and HTML, because your'e drawing these things.

foolip: That's the point.

foolip: We had a proposal to add a specific hit-testing API, but we found a better idea recently, so I will show the source

foolip: Source is the two cards, each is a <div> that's the child of the <canvas>

foolip: By default, all elements are painted at the top left (0,0) so if we want them elsewhere we have to move them.

foolip: We draw the element, adjust by devicePixelRatio, and then use a CSS transform property to move it.

foolip: But this is something, we would like to just call getTransform and have it do the right thing

foolip: But need to work on this. Set up the transform automatically when you call drawEleentImage or something

foolip: Hoping to also discuss the internals of this, implementation concerns in other engines to make this work

<anne> foolip: Want to discuss hit testing and the processing model.

foolip: This paints the element immediately, and then you can read back the pixels, so you need a clean layout state

foolip: Given how we expect devs to use it, we don't think it's going to be a problem, since theyr'e likely to use resizeObserver etc.

foolip: But there's some concerns around timing

foolip: So that's the demo! Let's do some discussing!

<anne> masonf: how are the elements exposed in the AT tree?

masonf: Can you talk a bit aobut how the elements are exposed in the a11y tree?

foolip: Both hit testing and a11y tree, there's an opt in here. There's a new attribute on the <canvas> element (currently called 'layoutsubtree'). The attribute lets us change some defaults.

foolip: if you use the attribute, everything will be hit tested, and everything will be exposed to a11y tree

masonf: Only children, or all?

foolip: Problem is we can't know when you stop drawing an element

foolip: So rather than putting it in the a11y tree and hit testing when you draw it

foolip: Would need to hide it or something

foolip: We want a very strong incentive to keep that subtree in sync with reality

foolip: ...

foolip: Making them hit-testable, people will be more likely to notice there's a problem and remove them from the tree as they should.

emilio: Seems to assume you can paint on main thread with all the CSS rendering, and do synchronously
… it constrains how you can implement it
… We've made a lot of effort to move a lot of rendering to the GPU, and this prevents or causes a synchronous round trip to compositor, which is not great
… forces us to draw on main thread
… Definitely better than what people do now for small stuff
… but if point of this API is to make these interactive use cases very easy to do
… people will inevitably use it for a lot of interactive stuff
… and problem with canvas is then you need to repaint every frame
… and you don't get a lot of the painting optimizations you'd otherwis eget
… I think it would be better if we came up with a way that you could still draw the element on the compositor
… It's annoying for WebGL, because you need the texture size up from, but seems workable
… API shape would need to change
… but if you say hey, drawElement, it could stash a reference ot the element in a way and re-use the normal rendering pipeline to eventually get that into the <canvas>
… That's a bunch of constraints like you can't immediately read pixels...

jake: why does it need to be synchronous?

emilio: also the fact that you're supposed to draw the element in the current state that you need to paint. You drawElement and then change innerText. Can't wait for regular rendering to update
… want to use the same compositing round trip

foolip: Would love to hear from other impls

smaug: cross-origin iframes creates a problem
… not even painting, but just hit-testing is an issue

foolip: What should happen is having no effect that you can observe
… should be as if not there

schenney: In Chrome right now cross-origin iframes are not drawn and not hit-tested

<Zakim> Jamie, you wanted to ask about how content outside of HTML-in-canvas is exposed to accessibility, canvas fallback content

Jamie: So it's hit-testable the same way normal HTML is hit-testable. That would translate to a11y just fine
… But ocntent outside the HTML canvas, not accessible. Except fallback which is not hit-testable
… If we are seeing more content insied HTML <canvas> that's not accessible, seems a problem

foolip: Do you mean for cases that mix fallback content and rendered content?

Jamie: [missed explanation]
… Seems like we'd get only half the accessibility

foolip: Let's say it's complicate, and game with WebGL menu

<schenney> I can answer to some extent.

foolip: you'd have a problem with how to expose those bits

Jamie: We'd say the stuff inside is accessible, but not the other stuff

foolip: Expose other content

Jamie: Then you'd have a hit-testing problem

Jamie: We need to solve this one way or another. Happy to be part of the conversation.

foolip: People talking about using this, use case where you have UI drawn in canvas is not that big
… more like text with some graphical effects

Jamie: Yes, but if people can use it they wil

schenney: Follow up on a11y
… we definitely won't be making it any worse
… One advantage of hit-testing canvas children is that you're more likely to notice if your fallback content is incorrect because you'll hit-test it
… Weak argument but worse to not see at all
… If you want HTML to stack right to hit test, you'd need to put some DIV or something to represent the canvas in the middle
… You will need some text to put in that node to put in that drawn layer
… So that will also help
… By no means do we claim this will fix all the canvas a11y problems, definitely more to be done there.

ntim: I heard some talk around cross-origin iframes. Are there any security considerations?

jake: Anything sensitive isn't drawn. Cross-origin images, iframes, not drawn.

foolip: [shows spec] This is list of things we would not draw: cross-origin data, system colors, spelliing and grammar markers, search text, visited link info, autofill info

jake: You lose functionality if you paint a form

foolip: A little bit yes, but with ?? options is to build everything with JS or they use system theme color in those form previes
… but we're building form for other peopel to use. If it has default style, it's stil lusable
… But [missed]

emilio: Is the attack here being able to read the pixels, or more subtle like timing attack?
… As a developer it might be a good compromise to ...
… similarly, async thing, that needs to prevent readback, but that forces you to keep your ocntent unmodified if you want it to be drawn
… otherwise your hit testing breaks, if you drawElement, change content, and drawElement again

foolip: Issue is you can't taint WebGL. It goes into a shader, can extract information
… So we want to work without tainting first
… but open to a tainting mode
… but trying to make as useful as possible without tainting, and it looks like we can get pretty far

zcorpan: Have you thought about not leaking sensitive info injected by web extensions?

<tantek-projector> +1 zcorpan

schenney: I'd have to think about that

chrishtr: If injected into DOM, the site can read it anyway

emilio: Could put it into a closed shadow root

<br type=lunch>

Some recent Naivgation API spec issues

Some recent Navigation API spec issues

Some recent Navigation API spec issues

<westbrook> smaug: Navigation API is part of Interop 2025

<westbrook> smaug: it's been in the spec many years as well as some tests

<westbrook> smaug: however, those tests don't _always_ match the spec

<westbrook> smaug: specifically in some timing issues

<westbrook> smaug: how do we ensure that when we write tests they follow the spec and how do you get right to submitting an issue when we find issues with the spec

<westbrook> smaug: is there something in our processes that do not require us to review the tests that we write?

<westbrook> smaug: are we not following the active changes of the specs over time?

<westbrook> anne: we mainly trust the implementation process, which isn't always great

<westbrook> anne: sometimes even coverage isn't sufficient to follow the actual implementation/spec in other implementations

<westbrook> anne: these cross implementation processes are hard, so following the other engines in their native processes can be awkward

<westbrook> smaug: what can each of our orgs do to make this easier for other teams

<westbrook> smaug: this has shown itself in various recent things, not just the Navigation API spec

<westbrook> anne: in this case, maybe it was igalia that did much of the early implementation

<westbrook> anne: webkit maybe simply followed the tests when they came behind

<westbrook> noamr: when we make tentative tests into non-tentative tests, maybe this is a better point to align across implementors and spec on these features

<westbrook> noamr: coverages, correctness, etc. before getting into phase 3

<westbrook> noamr: it's possible in large specs like Navigation API might not be possible to fix

<westbrook> noamr: the bigger the change, the bigger the chance for human error

<westbrook> noamr: the first implementation has a large number of interaction loops (internal, with the spec, with origin trials, etc) that can lead to misalignment in general

<westbrook> anne: I've seen the same with Scoped Custom Element Registries, being ahead of others at implementation time can be difficult

<westbrook> foolip: chromium looking into what a "comprehensive test suite" looks like in ensuring that their contributions are hitting some similar bars in this area

<westbrook> foolip: can share examples

<westbrook> foolip: experimentally, I've attempted to use AI to test alignment between specs and WPT tests that reports bugs, misalignments, etc as a high level comparison

<westbrook> foolip: won't internalize how things work or intersect with each other, but can call out "ooopsies" around things not tested, etc.

<westbrook> foolip: possible that this sort of process with even a 20% failure rate would be a good step up from current approaches

<foolip> example report from the AI tool: https://gist.github.com/foolip/cfa35117bb379b8b0f3bfc1b49d1119e

<westbrook> zcorpan: if there's a review item that involves relating changes in the implementations back to spec issues/changes that would be helpful

<westbrook> zcorpan: maybe as implementation gets further from the core of a team this isn't happening quite as much

<westbrook> zcorpan: less likely to happen during incubation time

<foolip> This is the kind of prompt that I used, which also includes our WIP definition of "comprehensive test suite": https://gist.github.com/foolip/2cb9484572fa5f5c2fa0c632d5719771

<westbrook> smaug: mozilla has started doing line by line comments around what they've implemented and how it related to the spec

<westbrook> domfarolino: trying to pair fast iteration locally with tests in WPT

<westbrook> domfarolino: this API is huge and the fact that it came together with just 14 bugs is great

<westbrook> smaug: yes, but why was the next implementor required to open them

<westbrook> smaug: realized this reality quite late in the process

<westbrook> domfarolino: did Chromium maybe not run into the same issue that Gecko did during implementation time

<westbrook> domfarolino: did igalia do most of the implementation?

<westbrook> anne: igalia not here after most of the work, but webkit follow behind what was there

<westbrook> foolip: in interop when tests are in a specific area that don't match the spec then we take them out

<westbrook> foolip: there's a test change proposal process for changing them and keeping them, but start with getting them off the sheet if they're not inline with the spec

<westbrook> foolip: that doesn't resolve the larger interop problem between the implementations

<westbrook> smaug: should we then exclude these 7 failing tests?

<westbrook> smaug: would the 4 after that need to change?

<westbrook> smaug: foolip: shared an additional test beyond that that is misaligned

<westbrook> smaug: the spec is very clear, but the tests are testing chromium's implementation

<westbrook> smaug: there's an extra microtask in the implementation there

<westbrook> noamr: I wanted to make sure that I agree with that process because it is the only spec'd case where there's only one microtask instead of 2

<westbrook> noamr: we can decide on either, no strong opinnion

<westbrook> miketaylr: this process issue, is it more acute during "Interop" or is it general across other APIs

<westbrook> smaug: see trusted types, even though there were a lot of tests, they we're all in alignments/passing in implementations

<westbrook> miketaylr: can we then simply correct the tests

<westbrook> anne: sometimes yes, but that hurts "Interop" and _sometimes_ web compat.

<westbrook> noamr: yes, we want to ensure that following the spec allows for not breaking compat.

<westbrook> foolip: have you submitted PR with the changes required to match the spec?

<westbrook> foolip: that would be needed at some point.

<westbrook> foolip: you might just merge the PR, and if it just gets blocked on interop the team will review it on about the weekly basis

<westbrook> foolip: there's less paper work that way

<westbrook> anne: if you do that, if you upstream updated tests from your local implementation doesn't that cause issues?

<westbrook> foolip: we have this with chromium, things being blocked for a week aren't that big of a deal

<westbrook> anne: what if there are further tests?

<westbrook> foolip: harder, requires the team to interceed, but doesn't happen that much

<westbrook> noamr: the removal of "waitforall" woudl likely be best at the Interop level, so we have time to confirm we don't break compat

<westbrook> noamr: we can find the places that require the current timing and x-browser confirm their reliance on it

<westbrook> zcorpan: we've run similar and not found issues so far

<westbrook> foolip: is the issue that waitforall is one microtask or two?

<westbrook> noamr: alters the order of events and nativations

<westbrook> zcorpan: especially if you have two sync navigations

<westbrook> zcorpan: changes the communicated results of the algorithm

<westbrook> noamr: but still mostly an edge case.

<westbrook> smaug: feels a little better running through these things together

<westbrook> smaug: we'll submit PRs removing these tests

<westbrook> noamr: not failing sites that use these APIs make removing these from Interop feel good.

<westbrook> foolip: then can we just change the tests?

<westbrook> noamr: change the tests and exclude them!

<noamr4> ScribeNick noamr4

Optimization to avoid duplicate navigations

Rakina: Rakina from Chrome, optimizing navigations
… navigation, and soon after another one

<noamr> ... potentially wasteful. first request sent, second is a dup

<noamr> ... proposal is to not waste the ongoing navigation. based on some criteria

<noamr> ... url, initiator, cookies, headers, start delta within a timeframe

<noamr> ... decreases the response from the server. decreases latency

<noamr> ... we see decreases in exact duplicates, server responses that were never shown to the user (tested by a beacon)

<noamr> ... various approaches on how to do this; ignoring the 2nd nav entirely; this is web observable

<noamr> ... e.g. webdriver events, service workers, navigation timing timestamps, click handler fired twice but navigated once

<noamr> ... opt-in? URL with specific params? headers? needs to be before. URL

<noamr> ... approach 2: transform the first nav to be the 2nd nav. pretend that the first cancel the first nav, but really ignore the 2nd and transform the 1st to the 2nd

<noamr> ... can also be weird if fetchStart/navigationStart are flipped

<noamr> ... approach 3: network layer. cancel the 1st navigation but pass the network pipe to the second navigation

<noamr> ... can be kind of like prefetch

<noamr> ... complex in spec/impl

<noamr> anne: how is this different from 2?

<noamr> rakina: it's updating the properties of the navigation

<noamr> ... in all those approaches SW is not visible

<noamr> ... wanted to get some thoughts

<noamr> ... which layer? navigation layer? network layer? criteria?

<noamr> ... same URL, referer, history, GET, <=3s, cookies

<noamr> domfarolino: 1 vs. 2, we're still dropping one of the navs.

<noamr> rakina: 1/2 mostly matters in implementation

<noamr> rakina: for (2) we actually cancel the 1st navigation

<noamr> domfarolino: (1) seems more logical. it's weird to cancel the 1st

<noamr> ... hard to judge the differences

<noamr> anne: all this only applies before the navigaiton is committed

<noamr> domfarolino: with (3) what would be the navigation timing

<noamr> ... do we get 2 results?

<noamr> rakina: it's only visible once you committed

<noamr> e.g. fetchStart

<noamr> rakina: maybe (1) is the simplest approach

<noamr> anne: the problem with (1) is that the cookie check is async

<noamr> domfarolino: either way it would be parallel

<noamr> smaug: about the problem itself, I wonder if this is just a UI issue

<noamr> ...: you probably don't know that you're navigating/loading anything

<noamr> rakina: might be. sometimes it's a matter of milliseconds

<noamr> rakina: we collect the timestamps when initiating the navigations

<noamr> euclid: so usage statitics?

<noamr> rakina: yes

<noamr> zcorpan: in option 2/3 re. navigationStart, would it be from the 2nd navigation in (2) (3) and the 1st navigation for (1)?

<noamr> rakina: we might need to expose navigationStart

noamr: specwise we can do this already, deal with it as if it was the HTTP cahce.
… someplaces we do things differently, since fetch doesn't specify exactly what the cache is.
… in some case, the response might not be there already.
… it's vague what's happening in HTTP cache.

zcorpan: it's the model with the cache, stored with the full response, use it while streaming

noamr: I guess that's not allowed in the model, but that's what we want, too.
… it would look like there are two separate fetches, the second would be an immediate navigation.that would expose that it wasn't immediate.
… I think we should do something similar to option 3. there are some places where in flight you could call this...???
… preloads are before service workers.

anne: fetch describes fetch layer and network layer separately.

noamr: with preload specifically it doesn't do another fetch

<zcorpan> maybe pretend that the first navigation was a nav prefetch

<noamr> kouhei: strong for option (1) is that it's most straightforward

<noamr> kouhei: service worker is before HTTP cache, so it would be before SW, so a new cache layer

<noamr> ... so my preference would be option (1)

<noamr> domfarolino: also for option 1

<noamr> zcourpan: we can pretend it's a speculationrules prefetch

<noamr> zcorpan: only in the web exposed sense

<noamr> zcorpan: like option (1), and add activationStart for the timing of the 2nd navigation

<noamr> domfarolino: what does webdriver do?

<noamr> zcorpan: if we cancel (2), it would look like the 2nd nav was cancelled

<noamr> domfarolino: why expose it as a prefetch?

<noamr> zcorpan: it's the closest thing I could think of

<noamr> domfarolino: I think we should cancel the 2nd navigation and point navigation timing to the 1st. It's the most consistent

<noamr> anne: could we race the navigation? do you have metrics like network topology changing between navigations? What if the user ends up pressing refresh? Is that a bypass?

<noamr> rakina: there is a time threshold

<noamr> kouhei: can we leave some of this to be implementation defined?

<noamr> domfarolino: I would be fine with that

<kouhei> ^ specifically about the timing threshold

<noamr> zcorpan: I prefer it to be specified and interoperable

<noamr> zcorpan: might be web compat issues

<noamr> takashi: what if the nav opens a new tab

<noamr> rakina: we check if the frame is the same

<noamr> domfarolino: can we resolve on option 1, and try to spec that with some threshold we agree on later in an offline discussion?

<noamr> rakina: currently it applies also to programattic navigations

<noamr> domfarolino: we should not do this for user-involved navigations

<noamr> anne: not sure about that

<noamr> cwilso: let's follow up on this as a detail

<noamr> whatwg/html#11819

Allow deferring commit of a same-origin cross-document navigation

<noamr> https://github.com/w3c/csswg-drafts/blob/main/css-view-transitions-2/two-phase-transition-explainer.md#allowing-the-author-to-control-the-commit-scheduling

[noamr explains the link above]

noamr: we want to experiment with pre-rendering the subsequent document in the background

noamr: and we want to let the old document delay the navigation commit so it can finish some processing

noamr: all of this with the goal of reducing the transition time between two same-origin documents the end user navigates between

anne: with the possible usage example, how does the deferCommit know when the next document is ready?

noamr: it doesn't, it only renders a skeleton

noamr: this is not directly related to view transitions, but it's useful for view transitions

noamr: as. they're the only API that let's you customize the navigation experience

sisidovski: what's nextDocumentReadyToRender?

noamr: I think bfcache or pre-rendered

jake: what happens if you go back, as now the skeleton would be there which makes the document unusable

noamr: example is incomplete, you'd need to do more

noamr: could use some improvement

Takeshi(?): do you have more future plans or if you just want to do this we could also extend view transitions?

noamr: you might want to defer for non-UI reasons, such as storing app state

noamr: I'll make it a proposal and propose for Stage 1

Out-of-order HTML streaming #11542

out of order html streaming

github: whatwg/html#11542

<foolip> presenting https://github.com/WICG/declarative-partial-updates/blob/main/patching-explainer.md

<noamr> https://github.com/WICG/declarative-partial-updates/blob/main/patching-explainer.md#interleaved-patching

noamr: this is about out of order streaming, discussed at WHATNOT a few times
… a lot of frameworks / websites do
… they put some parts of the HTML first, and as the server knows more stuff they bring that stuff in
… right now that works with inline script tags and such, which is not as fast as it should
… so would be good if sites wouldn't have to reinvent it
… we settled on this approach, a placeholder with contentname
… and a template with contentmethod attribute
… the internal children would have the same tagname and contentname, and children would stream directly into the placeholder
… forcing the same tagname causes the parser not to change considerably
… don't have to change raw text or anything like that
… we have 4 content methods
… replacechildren, replacewith, prepend and append
… this is about it in terms of content for the first iteration of it

foolip: [screenshares example]

foolip: lots of internal details we could talk about

emilio: in this replace example, would you actually replace the domnode or just change the attributes?

foolip: we have this wireframe example with the classname
… and replace would end up "removing the attribute"

anne: This would change the node identity

emilio: that was the question, thanks

westbrook: you can get this by attaching a shadow root on the body and attach out of order content via slots

noamr: that solves only some of the use cases

westbrook: what's the use case for append / prepend

<jridgewell> Incrementally streaming unknowably many children into the content, interleaved with streaming to other content

ann: can you elaborate on the slot stuff?

emilio: you can have a shadow root on the <body> with different <slot>s and stream the body content into each slot separately
… which achieves the same thing

YY: looks like this example the parsing comes before
… we try to do the patching after the rendering

<westbrook> Example of the above shadow DOM approach: https://ooo.lamplightdev.workers.dev/

YY: and patching would change the contents

foolip: you mean after the document would be parsed already?

noamr: Rendering can happen during this time, but if you finished parsing already you can't [...]
… we first had it as one proposal, with javascript streaming, which would do what you want
… we made those proposal totally different in terms of spec or api

foolip: for your use case just keeping the stream open for longer would be more useful

YY: I want to just render a template but after rendering patching the contents
… is that supported?

noam: As long as the response didn't close yes
… whether that's the optimal architecture vs closing and starting a new stream not sure, not opinionated

foolip: you could combine it with the JS API to stream templates to modify the existing document too
… and use the same markup

rniwa: one question, in the example you had a template element instead of an <aside for the contentform>
… why is this not in the <template>?

foolip: It's important that we handle the parser ??
… let's say the first thing was a table

anne: insertion mode inside a table depends on the first tag

noam: script is a mess
… you need to put that in a special text mode
… and then if you don't support the feature you interpret it

rniwa: but you only support one element within a template?

foolip: no, multiple

rniwa: how does replace deal with this?

noam: The template content method means this is a batch, each child within is separate
… if you have another <aside> with a content name it'd be like a new replace

foolip: so let's say you have two different things
… then you patch them in whatever order

rniwa: so what if the element name with the attribute is different from the original?

foolip: different ways to write it in the spec, but the rule is look up the first element in the tree using contentname
… then the local name and namespace have to match, if they don't then you don't keep looking for other elements

keithamus: Curious about script, what happens if I replace a script?
… e.g. <template contentmethod=replace><script contentfor="...">...</script></template>

foolip: same rules apply, you have script with no children and pass it a text child it'd execute, but it falls out of that situation

keithamus: what happened if I modify the dom before reaching the template
… like adding a contentname?

foolip: just works, would use the dom at that time

keithamus: this is like htmx and ??, have you asked those developers and see what's missing?

noamr: Yeah also github, we have various responses, some are public in the repo
… a lot of this is after all those feedback
… there was another feature request to replace a range not between elements, which could be an extension to this
… we've given lot of discussions between people that are doing

keithamus: any feedback on what's missing?

noamr: yeah the range thing and script comes up

keithamus: I can introspect the template after the parsing is done?

foolip: just like <template shadowrootmode>, that's not re-inserted, additional nodes go in the void

keithamus: so silent failures if I made a typo?

noamr: Yeah I think we need to come up with error event

hsivonen: the <script> topic is very concerning
… if the parser flushes within a text node that'd cause a partial script to be executed
… the model for script should be closer to the regular execution, you run it at the end tag instead of allowing partial insertion of text nodes
… there was a remark about whether the html comes from the document is distinct from the JS
… the streaming sanitizer supposed to work with the JS API or is it also expected to interact with the network stream?

foolip: sanitizer applies for streamHTML (the js api)
… the main parser doesn't have a sanitizer, there's a need that would be worth discussing
… first question about <script> is a great point, not 100% sure what does per spec or as implemented, we shouldn't do that

noamr: would be a bug to fix

hsivonen: if the method is not append / replacechildren, what is the reference point in the document that we'll be inserting to?
… if the <aside> element previous siblings and next siblings, what is the insertion point?
… replace replaces the element itself, is it always going to be one element of the template, or can you replace a node with multiple?

foolip: it'd replace multiple times
… prepend is the trickier case
… the way it currently works is when we find the content name, then save the first child of the content target, and then when we insert before that node as long as it's still under the same node

noamr: insertBefore semantics, and if it's not valid it errors the whole thing

hsivonen: is this something existing libraries are demanding

noamr: Replacing a range was the main use case

hsivonen: why is it important to be able to replace a range without a wrapper?

noamr: rows of a table or <meta> in <head>

anne: if there's a lot of content at the end the load wouldn't fire, is that problematic?

foolip: then you'd use the JS API

(mainly DOMContentLoaded, but yes)

foolip: this is not intended to long wait, just waiting for the backend to fill the content

westbrook: would this recurse, e.g. if I replace with a child that had contentfor...

foolip: no, the parser is going to insert an element

noamr: It recurses the root for looking up the name is the parent of the template

westbrook: so if I have contentname=first and replace that with <div contentname=first><div contentname=second></div>
… would it recurse if I have a <div contentname=second> on the template?

foolip: it wouldn't recurse just apply the same thing again

westbrook: would that work?

<masonf> but who's on first

foolip: yes, we'd look by contentname

keithamus: you said the template parent's children?
… or descendants?

noamr: descendants of the template
… exception would be if the template is a child of the <body> where the root would be the whole doc

JakeA: The same issue with <script> happens with <style>
… and maybe <media>

foolip: video resource selection is weird but that makes it work in this case

JakeA: what happens during innerHTML

noamr: It works but the parent of the template is what you're inserting into
… so you're only patching what's on your template

keithamus: weird that it works with innerHTML because declarative shadow root doesn't
… would be good to double-check why

zcorpan: the reason for that would be to specify which shadow root

rniwa: main concern was script execution, a template insertion shouldn't execute script

anne: we should do the same here

hsivonen: is the patching itself intended to be streaming, in the <aside> example, do we first replace, then stream contents, or replace with the whole <aside>?

foolip: it's streaming
… which means the example is a bit weird because the wireframe has 3 and if the parser stops in the middle it jumps
… maybe we should look into that

clarifying worker lifetime relationship

Further clarify worker lifetime relationships

dom: this is a feature to extend the lifetime of workers

whatwg/html#10997

dom: people currently run into issues doing work at this time as it's unreliable. Some are moving this work to service workers, but that makes the service worker less responsive.

dom: two ideas: 1) PageHideWorklet 2) small extension to shared workers

dom: there's a specification PR for the second of these ideas and some tentative support from Mozilla

dom: there's an open discussion on the bfcache

[scribe missed a bit]

dom: how do you avoid holding the lock forever?

[missed]

dom: Chromium is experimenting with this

Yoshisato: current implementation doesn't care much about Web Locks or bfcache

Yoshisato: it currently doesn't bfcache, so extended lifetime kinda works

dom: does Chromium not evict documents?

?: we do

dom: the current behavior in Chromium is that when the shared worker terminates and all the client documents are in bfcache, they are evicted

?: the freezing just solves the eviction, it doesn't help with the locks

dom: if there's a reasonable answer for bfcache, can we have support from Mozilla?

zcorpan: yes

dom: need to be more rigorous about bfcache and then we can merge it

anne: don't forget about tests

?: extended lifetime is 5min in Chromium

dom: could maybe add some WebDriver API

<rakina> ? is fergal

fergal (? above): it'd be good to have more WebDriver coverages in specifications

dom: I'm happy

Bikeshed (away)

foolip: HTML is written in a dialect of HTML called Wattsi

foolip: nobody that's still around really knows how it works, but Mike(tm) knows a fair bit

foolip: as such I've been looking into a shift to Bikeshed

[foolip shows the setup]

[quickly pushes a WIP branch so people can try it at home]

foolip: when building you currently hit 50k of warnings/errors

foolip: but you don't need to worry about that [I think we should]

[foolip is quite proud of the HTML standard kinda working :-p]

foolip: Wattsi uses data-x attributes for uniqueness (with text content fallback) and Bikeshed is quite different from that with lt and for attributes, and more

<smaug> Does this bring the rather bad animation (speced/bikeshed#2772) to HTML spec?

anne: we need to manually set the IDs to data-x so that the IDs are preserved

dom: do you create nested structures with for attributes and such as is ideally the case?

foolip: thus far I've not tried to account for that

anne: I think we might have to investigate existing `<dfn>`s so we can do this properly

anne: we already did this work for most of the IDL members so it seems tractable

zcorpan: cross-specification xrefs are also different, need to be removed from HTML as Bikeshed handles them

foolip: I was thinking of doing that after to make the diffing better

foolip: I also want to compare the generated DOM which is tricky

TabAtkins: multi-page output is next on my list

foolip: lxml?

TabAtkins: very close

foolip: replacing html5lib with lxml was a good speedup

[shows some graphics on screen]

foolip: a broken build is possible in <10s [hmm]

zcorpan: 10s seems acceptable to me [presumably if the output is non-broken]

Mike(tm): what's the wall-clock time? I need ms

TabAtkins: on my crusty laptop it's 65s without any kind of improvements; should be substantially faster with these improvements

Mike(tm): Wattsi is 12s for me, 60s seems very slow

TabAtkins: there's also some Rust conversion going on that might make it even quicker

<TabAtkins> "might", it definitely will make it significantly faster

keithamus: I think we should move ahead even if it's slow because it can be faster

dom: I think it needs to be faster

Mike(tm): I don't feel strongly about the perf, I was trying to paraphrase Domenic whose workflow needs a quick turnaround

dom: 24s seems acceptable

zcorpan: ditto

zcorpan: I'm assuming here we're going to improve beyond 24s

TabAtkins: I'm hoping we can get to 10s if we do all the todos

dom: how is the race between fixing issues and perf going to work out?

foolip: fixing issues is going to win

TabAtkins: agreed

foolip: how much Bikeshed Markdown should we adopt?

Mike(tm): I think for contributors full Markdown would be the biggest win, if we could get their eventually

zcorpan: not sure HTML should do block-level Markdown

anne: I care mainly about doing the `<dfn>`s and such properly; syntax feels secondary, but if it makes it easier we can convert the lot I suppose

Mike(tm): what about SVG?

TabAtkins: multi-page input already works, but multi-page output doesn't

TabAtkins: but that's being fixed

zcorpan: HTML Dev Edition?

foolip: TBD

TabAtkins: you can use the Status feature

Minutes manually created (not a transcript), formatted by scribe.perl version 248 (Mon Oct 27 20:04:16 2025 UTC).

Diagnostics

Succeeded: s/???/ThreadLocalStorage in C++, not to the web localStorage

Succeeded: s/???/jridgewell/

Failed: s/(misssed),/browser originated events have no obvious context to propagate, like `onload`

Succeeded: s/[missed]/why does it need to be synchronous?

Succeeded: s/???/Jamie

Succeeded: s/noamr/smaug

Maybe present: ?, andreubotella, ann, anne, chrishtr, dom, domfarolino, emilio, fantasai, foolip, hsivonen, jake, JakeA, Jamie, jridgewell, keithamus, leo, Mike(tm), mmocny, nicolo-ribaudo, noam, ntim, Rakina, rniwa, schenney, sisidovski, smaug, snek, TabAtkins, Takeshi(?), westbrook, Yoshisato, YY, zcorpan

All speakers: ?, andreubotella, ann, anne, chrishtr, cwilso, dom, domfarolino, emilio, fantasai, foolip, hsivonen, jake, JakeA, Jamie, jridgewell, keithamus, kizu, leo, masonf, Mike(tm), mmocny, nicolo-ribaudo, noam, noamr, ntim, Rakina, rniwa, schenney, sisidovski, smaug, snek, TabAtkins, Takeshi(?), westbrook, Yoshisato, YY, zcorpan

Active on IRC: alice, alisonmaher, Ananya, anne, astearns, cwilso, domfarolino, emilio, fantasai, foolip, frehner, hsivonen, JakeA, Jamie, jridgewell, Jxck, kizu, kouhei, kouhei2, LeoL, masonf, Mike5, miketaylr, nicolo-ribaudo, noamr, noamr4, noamr5, ntim, rakina, rniwa, schenney, sisidovski, smaug, TabAtkins, tantek, tantek-projector, westbrook, YY, zcorpan