- From: Lea Verou <notifications@github.com>
- Date: Fri, 13 Feb 2026 23:23:40 -0800
- To: w3ctag/design-reviews <design-reviews@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3ctag/design-reviews/issues/1195/3901305484@github.com>
LeaVerou left a comment (w3ctag/design-reviews#1195) On a high-level, I have quite a few reservations about these efforts to extend specifiers to CSS in such a specific, ad hoc way without considering the broader platform implications. I think extending specifiers to other resources and other import sites is a *fantastic* idea, but we need to at least have a plan for how it will all fit together in the end, otherwise a decade later we will end up with 10 different ways to define and import specifiers, all with subtly different implications and no mental model that justifies their differences in a user-centered way. This is not a bottom up problem that we can solve incrementally and hope the pieces will just _happen_ to fit together in the end. > 1. The imperative `adoptedStyleSheets` API does not perform a fetch, and we wanted the attribute to be consistent with the API as much as possible. The imperative API accepts `CSSStyleSheet` objects, not URLs, and any `import` statements *do* trigger a fetch. Also, while consistency between corresponding JS and HTML/CSS APIs is useful where it makes sense, HTML and CSS are generally reactive languages and thus author expectations are different. In reactive languages, ordering effects are generally avoided: If A && B produce C, which comes first shouldn't matter. This part violates that expectation: > `shadowrootadoptedstylesheets` accepts a space-separated list of specifiers. Currently, for each specifier, the module map is queried, and if a style module is present with that specifier, it is added to the `adoptedStyleSheets` array for the declarative shadow DOM that it is associated with. If a style module with that specifier (or even a specifier mapping) is not present at the time, what happens? Is the module map ever revisited or does the stylesheet just fail to get adopted? Now authors have to learn at what exact point the module map is looked at, and how to make sure their modules have all loaded before that point. It’s exactly these types of ordering effects that we try to avoid as much as possible when designing HTML and CSS features. I would swear we introduced a design principle on this when I was in the TAG but I can't find it, not even in the issues list. Perhaps @jyasskin or @martinthomson has seen something around it. If I'm hallucinating it, I'm happy to file an issue. Ordering effects aside, I’m not aware of any precedent of a web platform API that lets authors use an imported module in some way without providing any means to import it. The closest I can think of is `import.meta.resolve()`, but that just resolves a specifier, rather than _doing_ something with a resource. The examples of `<blockquote cite>` or Microdata attributes that was mentioned in the other thread are adding metadata, not importing for usage. This is an important difference. Nothing breaks if `<blockquote cite>` is not fetched. Stuff breaks — _badly_ — if adopted stylesheets are not fetched. Also, reading the explainer it appears that the attribute accepts both URLs and specifiers, not just specifiers, and this behavior is even weirder with URLs. > 3. If it did perform a fetch, there would be no mechanism to catch errors via `onerror` (or success via `onload`), as the `<template>` tag is discarded after parsing. Also, `<template>` lacks attributes like CORS, blocking, and more that are necessary for a robust fetching mechanism. All good points! But to me, these seem like API smells indicating that perhaps the current syntactic approach may not be the best, not reasons that justify the current behavior. Yes, it's good to have error handling. Yes, it's good to be able to set parameters on the request. Ideally, we should try to find a way that allows for these too (even if not MVP). But I would still consider it a top priority to avoid missing stylesheets entirely. I would note that the goal here is not to avoid a separate element. A separate element may well be warranted! The problem is that the API design of the current feature implies that the stylesheets will be fetched. `modulepreload` is supposed to be a performance optimization, not something that *breaks* functionality if not present. Also, going into the weeds here briefly, but the `error` event could well fire on the element itself, or even on the `<template>` before it's removed, so that capturing still catches it. > 4. The primary use case we've seen for `shadowrootadoptedstylesheets` is for declarative modules, which don't need a fetch. Alternatively, we could scope `shadowrootadoptedstylesheets` to only declarative modules, but that also seems inconsistent. It seems inconsistent for the same reason it's problematic to [overfit](https://medium.com/design-bootcamp/overfitting-and-the-problem-with-use-cases-337d9f4bf4d7) to declarative modules: There is no author-facing reason to scope the feature to declarative modules. It is a perfectly normal user need to want to specify adopted stylesheets for declarative shadow roots. Declarative modules may be a louder use case, but I can see many authors seeing the attribute in documentation and thinking it's a good idea to use it, and fundamentally there is no reason why it shouldn't work. As an exercise, try to explain to the average web author (who — like 99+% of authors — is not involved in standards or browser vendors) why this attribute doesn't work. > 5. `adoptedStyleSheets` is an array, and the order matters for CSS rule application. Each fetch response would trigger an FOUC, and style computation must be rerun for each load completion. Any mutations to `adoptedStyleSheets` while the fetch is loading would trigger more style changes, but this would match the existing behavior of `adoptedStyleSheets`. It being an array doesn't seem relevant, since the ordering in the array is specified via the URL order, regardless of how long resources take to fetch. Power users would want to avoid too much style recalc, and should have reasonable means to do so. However, we should not conflate performance/rendering speed with basic functionality. As discussed in the thread, A FOUC is *much* better than the stylesheet not loading at all. There is no reason to fetch anything or mutate anything if the stylesheet is already fetched, so there seems to be no downside to fetching as a fallback behavior. Authors can always pre-fetch, but it now becomes an optimization, not something that is required to make the basic functionality of the feature work. > 1. Leave as-is, and do not perform a fetch. > 2. If not already in the module map, perform a fetch, but with no CORS, error handling or load events, and with an FOUC for each fetched module completion. This can be mitigated with `<link rel=modulepreload>` ahead of time (and could be warned via the console). > 3. Only allow `shadowrootadoptedstylesheets` to accept declarative modules. This would avoid this issue, but is limiting and inconsistent. This could also be a temporary limitation. > 4. Create a new type of `<link>` tag that populates `adoptedStyleSheets`. This would handle CORS and load/error events, but still has ordering/FOUC issues due to `adoptedStyleSheets` ordering/mutation and adds DOM mutations to the mix. It will also be very similar to the existing `<link rel="modulepreload">`, which could be confusing. I think 2 is the right way forwards: things still *work* and `modulepreload` makes them performant. Everything else seems very surprising. IMO if it looks like it should fetch, it should fetch. -- Reply to this email directly or view it on GitHub: https://github.com/w3ctag/design-reviews/issues/1195#issuecomment-3901305484 You are receiving this because you are subscribed to this thread. Message ID: <w3ctag/design-reviews/issues/1195/3901305484@github.com>
Received on Saturday, 14 February 2026 07:23:44 UTC