You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[css-contain] Similar to window.matchMedia(), Container Queries should have a similar method #6205
CSS Media Queries have a method on the Window interface (window.matchMedia()) giving a script the ability to listen for media query changes. I propose that CSS Container Queries has the same functionality. However, I think this introduces some complexity, and therefore I'd like to present two thoughts for consideration:
Proposal 1
A new method on the HTMLElement interface possibly called matchContainer() or something similar. Reason it wouldn't be on the Window is due to the nature of container queries - not being based upon viewport size, but size of the container. However, this should be influenced by the question still pending, which is what is the default behavior of a container query when there is no contain property on any parent element.
Proposal 2
A new Observer of sorts, similar to ResizeObserver or MutationObserver where it's a bit more clear that it is listening for any kind of container change, and that it relays the container as a member of a ContainerQueryList. This would make it not pollute the HTMLElement interface, and instead be a DOM method. This would solely be used to identify when a container query is activated, and which items are affected by that activation.
Admittedly, the second proposal seems very similar to what ResizeObserver does already, but I feel it misses the connection that CSS Contain Level 3 is attempting to solve. This could be something that might be added to ResizeObserver, but might also be its own API.
The CSS Working Group just discussed Similar to window.matchMedia(), Container Queries should have a similar method, and agreed to the following:
RESOLVED: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existing
The full IRC log of that discussion
<dael> Topic: Similar to window.matchMedia(), Container Queries should have a similar method
<dael> github: https://github.com//issues/6205
<dael> miriam: Idea is have something similar for container queries. Claire (sp?) has provided a few options. Would be great to resolve on one. Or something else
<dael> astearns: 3 options: new method. new observer. reuse resize observer
<dael> fantasai: Possible use cases for both approaches. Could start with defining matchContainer since that's easy
<dael> astearns: You're thinking we would need matchContainer and either new observer or reuse resize?
<dael> fantasai: Yeah
<dael> astearns: Anyone with opinions about adding matchContainer?
<dael> TabAtkins: This would allow style queries in the matchContainer since they're under container query umbrella?
<dael> fantasai: Yeah
<dael> TabAtkins: Nice. Good
<dael> astearns: Prop: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existing
<dael> astearns: Objections?
<dael> RESOLVED: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existing
<fremy> FWIW I will not join the second call, I am going to bed, I think most issues I was involved in have been discussed already, or I left a comment with my thoughts. Talk to you all next week!
Is there anything new about this? We created a Designer with CSS parsing support (https://github.com/node-projects/web-component-designer) where we would need the "matchContainer" API to find the mathcing container queries
Just wanted to add that I ran into a use case where I wanted to be able to do;
window.matchContainer('(aspect-ratio < 16 / 9)')
Would have loved to be able to do this instead of writing some custom ResizeObserver which could potentially lead to performance issues if not managed mindful of re-paints for calculating/retrieving values.
Reacted by Rayat Rahman, Kari Söderholm, Xamir, mlemoine-clgx, Manuel de la Fuente, Rafael Pradella, Valera Melnikov, Brenton Simpson and Ferdinand Prantl
Note that many would just use the ResizeObserver w/o any interaction w/ an underlying container query css policy... but the point of this thread is to have something similar to mediaMatch. The things you can do in CSS might be tricky to otherwise detect in JS
Note also that Element.matches seems like a reasonable instictive "let me try this"... but it will not tolerate any container query
I was also surprised that there wasn't such api but that being said it can be very easily polyfilled using an invisible iframe in case you need this feature today:
I created a polyfill for Element.matchContainer()
It supports size queries and style queries and uses the CSS feature under the hood so it will only work in browsers that already support the @container queries CSS feature. All it really does is only adding the scripting API.
Reacted by Michail K, Bramus, Roderick Gadellaa, Nathan, Arad Alvand, Jonas, Josh Reynolds, Jean-Christophe Gueriaud, Nick Gault, Andrey Bobukh and 10 more
Wouldn't just checking a container element's offsetWidth when the window resizes be functionally the same as container query?
no? container queries could not only check for a size....
... and it should be possible to optimise container queries better than the resize observers. The change event on the container query is triggered only when it starts or stops matching. No need to throttle the observer event handlers, which can be triggered very often.
Will matchContainer() match on children elements of a container, the container itself, or both?
For example, with anchored container queries, I want to know when the applied fallback changes of the anchored element itself. It would be awkward to have to call matchContainer on a container's child (and not all anchored elements have children, necessarily).
I can imagine cases where you would want to listen on a container's child as well.
@teetotum If I understand it correctly, your polyfill only works on children of containers, and not on the containers themself. Do you have any insight into use cases for matching on children?
I suspect there are use cases where you don't know what element is creating the container, but want to know when the match changes. We could add something like Element.findClosestContainer('inline-size').matchContainer('min-width: 500px'), but that wouldn't support use cases where the container itself changes.
I think you hand over to this function only the container query string (same as you do with match media), so it could only work on the container
If the function accepted a container name somehow, would that allow it to work on children? Or are there other things I'm not thinking about?
Potentially we could have a second function matchContainerParent() that could be for the children. This function could also emit an event for when the container changes, even if the match doesn't.
The CSS @container query mechanism (setting aside the proposed workings of the .matchContainer() scripting API for a moment) can match an element when one of its ancestors (the container) meets the query condition. The container must be an ancestor, it can not be the element itself, posing as its own container.
This is by design; otherwise you would be able to write cyclic query conditions and style rules:
My understanding of the proposed .matchContainer() scripting API is, that it would behave exactly as its CSS counterpart. Nay, it must behave exactly so! Anything else would lead to great confusion and probably bugs. You could have some elements that are queried and styled via the CSS feature, and simultaneously have a programmatic query listener via .matchContainer() that observes the exact same query (for example to process the UI state further inside a React component which has some conditional behavior). Those two different ways to listen to the exact same query in the exact same DOM must match in the exact same way so the results are in sync. They must not differ.
There seems to be some confusion what role the element has in element.matchContainer(...) so let me try to clarify: the element is the descendant, not the container. An eligible container is searched in the ancestor chain of that element; when a container is found that is eligible (its container-type corresponds to the query type, container-name matches if one is required by the query) the condition is checked, and if met, the query reports matches as true. This means element is currently in a container that fulfills the query condition.
@jamesnw My polyfill does not enforce or assume any descendant and ancestor relationship for the watched element; so for the unlikely case that one day a container query type should be added to the CSS standard that would allow an element to form its own container, then this should just work fine through the polyfill.
You contributed a testcase to the polyfill recently; so I believe I know your use case for needing to match an anchored query for a custom styled <select> element. You don't need to pick the first <option> to get a reference to a descendant, you can use the dropdown element itself and it doesn't feel hacky anymore. It seems when a select is set to appearance: base-select i.e. custom styled the browser provides a popover that acts as a container, having <div class="dropdown"> (or whatever you put as content) as its child.
Yeah, iframe.matchMedia() checks the parent document, not the nested one. So here it's the same.
Also, consider @container (width > 30em), (height > 40em): width and height can even query different containers. So it's not clear what this means if the context element was supposed to be "the" container, especially if if only contains in one or zero axes.
For observing the element itself, better use ResizeObserver instead, and if needed for style queries or such, consider new observers in different issues (e.g. ComputedStyleObserver in #8982)
You don't need to pick the first <option> to get a reference to a descendant, you can use the dropdown element itself and it doesn't feel hacky anymore.
That doesn't seem to work in my testing, but was the first thing I tried. Even then, in that example the container itself is set on the ::picker() pseudoelement, not div.dropdown.
Also, consider @container (width > 30em), (height > 40em): width and height can even query different containers. So it's not clear what this means if the context element was supposed to be "the" container, especially if if only contains in one or zero axes.
I'd imagine a matchSelfAsContainer() (bikeshed) function would check if the element itself is an established container matching that. So If it has height and width, but only has container: inline-size, it would throw.
Then, a matchInsideContainer() function would check if the element is inside a matching container. I think there's probably need for both.
I suspect that anchored container queries would mostly use matchSelfAsContainer(), as it is more about state than context, and other queries would mostly use matchInsideQuery().
According to the css-conditional-5, it describes about figuring out the container from the ancestor.
For each element, the query container to be queried is selected from among the element’s ancestor query containers that are established as a valid query container for all the container features in the . If the contains unknown or unsupported container features, no query container will be selected for that . The filters the set of query containers considered to just those with a matching query container name.
I initially thought this api is likely matchSelfAsContainer. Maybe it is good to mention this on the spec.
FWIW, If we need like matchSelfAsContainer maybe, we can remove the word container from the API and probably this off the topic.
#13551 adds matchContainer() without the change event, so we still need to decide how authors observe changes, which the resolution left open. Options I see:
Reusing an existing observer. @robrezlooked into this: MutationObserver doesn't observe CSS changes, and IntersectionObserver and ResizeObserver only work through workarounds like toggling a property on a dummy element. ResizeObserver also misses style() and scroll-state() changes, which can flip without a resize.
Activity
andruud commentedon May 3, 2021
Why isn't the existing ResizeObserver (as-is) good enough to listen for resize events on containers?
css-meeting-bot commentedon Oct 6, 2021
The CSS Working Group just discussed
Similar to window.matchMedia(), Container Queries should have a similar method, and agreed to the following:RESOLVED: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existingThe full IRC log of that discussion
<dael> Topic: Similar to window.matchMedia(), Container Queries should have a similar method<dael> github: https://github.com//issues/6205
<dael> miriam: Idea is have something similar for container queries. Claire (sp?) has provided a few options. Would be great to resolve on one. Or something else
<dael> astearns: 3 options: new method. new observer. reuse resize observer
<dael> fantasai: Possible use cases for both approaches. Could start with defining matchContainer since that's easy
<dael> astearns: You're thinking we would need matchContainer and either new observer or reuse resize?
<dael> fantasai: Yeah
<dael> astearns: Anyone with opinions about adding matchContainer?
<dael> TabAtkins: This would allow style queries in the matchContainer since they're under container query umbrella?
<dael> fantasai: Yeah
<dael> TabAtkins: Nice. Good
<dael> astearns: Prop: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existing
<dael> astearns: Objections?
<dael> RESOLVED: Add a matchContainer method as proposed in issue. Keep issue open to decide if need new observer or if we can reuse the existing
<fremy> FWIW I will not join the second call, I am going to bed, I think most issues I was involved in have been discussed already, or I left a comment with my thoughts. Talk to you all next week!
jogibear9988 commentedon Jan 11, 2023
Is there anything new about this? We created a Designer with CSS parsing support (https://github.com/node-projects/web-component-designer) where we would need the "matchContainer" API to find the mathcing container queries
seedee commentedon Jun 6, 2023
Wouldn't just checking a container element's offsetWidth when the window resizes be functionally the same as container query?
jogibear9988 commentedon Jun 7, 2023
no? container queries could not only check for a size....
aradalvand commentedon Jul 26, 2023
I expected this to have already been implemented, such a shame.
7oque commentedon Aug 18, 2023
Just wanted to add that I ran into a use case where I wanted to be able to do;
window.matchContainer('(aspect-ratio < 16 / 9)')Would have loved to be able to do this instead of writing some custom ResizeObserver which could potentially lead to performance issues if not managed mindful of re-paints for calculating/retrieving values.
xamir82 commentedon Dec 13, 2023
No movement on this yet? No offense but do we have to wait another 10 years for something as basic as this again?
robrez commentedon Feb 28, 2024
Some experimenting with learning about container-query changes via JS
display: noneon a "dummy" element. Limitations: If the container is outside the viewportmediaMatch. The things you can do in CSS might be tricky to otherwise detect in JSElement.matchesseems like a reasonable instictive "let me try this"... but it will not tolerate any container query7 remaining items
jogibear9988 commentedon Nov 7, 2024
i think the other similar APIs like matchMedia and matches are on the coresponding object, so this also should be.
I think it the browser vendors should implement this in the near future. We have container queries but no API to check if a element matches...
alienself commentedon Dec 21, 2024
I was also surprised that there wasn't such api but that being said it can be very easily polyfilled using an invisible iframe in case you need this feature today:
https://github.com/tomhodgins/element-match-media/
teetotum commentedon Feb 24, 2025
I created a polyfill for
Element.matchContainer()It supports size queries and style queries and uses the CSS feature under the hood so it will only work in browsers that already support the
@containerqueries CSS feature. All it really does is only adding the scripting API.prantlf commentedon Jun 12, 2025
... and it should be possible to optimise container queries better than the resize observers. The
changeevent on the container query is triggered only when it starts or stops matching. No need to throttle the observer event handlers, which can be triggered very often.jogibear9988 commentedon Mar 5, 2026
We seem to have progress in chrome:
https://issues.chromium.org/issues/40887402
jamesnw commentedon Mar 5, 2026
Will
matchContainer()match on children elements of a container, the container itself, or both?For example, with anchored container queries, I want to know when the applied fallback changes of the anchored element itself. It would be awkward to have to call
matchContaineron a container's child (and not all anchored elements have children, necessarily).I can imagine cases where you would want to listen on a container's child as well.
lukewarlow commentedon Mar 5, 2026
I have use cases where I would want to match on the container itself not just children.
jogibear9988 commentedon Mar 5, 2026
I think you hand over to this function only the container query string (same as you do with match media), so it could only work on the container
jamesnw commentedon Mar 6, 2026
@teetotum If I understand it correctly, your polyfill only works on children of containers, and not on the containers themself. Do you have any insight into use cases for matching on children?
I suspect there are use cases where you don't know what element is creating the container, but want to know when the match changes. We could add something like
Element.findClosestContainer('inline-size').matchContainer('min-width: 500px'), but that wouldn't support use cases where the container itself changes.If the function accepted a container name somehow, would that allow it to work on children? Or are there other things I'm not thinking about?
Potentially we could have a second function
matchContainerParent()that could be for the children. This function could also emit an event for when the container changes, even if the match doesn't.teetotum commentedon Mar 9, 2026
The CSS
@containerquery mechanism (setting aside the proposed workings of the.matchContainer()scripting API for a moment) can match an element when one of its ancestors (the container) meets the query condition. The container must be an ancestor, it can not be the element itself, posing as its own container.This is by design; otherwise you would be able to write cyclic query conditions and style rules:
My understanding of the proposed
.matchContainer()scripting API is, that it would behave exactly as its CSS counterpart. Nay, it must behave exactly so! Anything else would lead to great confusion and probably bugs. You could have some elements that are queried and styled via the CSS feature, and simultaneously have a programmatic query listener via.matchContainer()that observes the exact same query (for example to process the UI state further inside a React component which has some conditional behavior). Those two different ways to listen to the exact same query in the exact same DOM must match in the exact same way so the results are in sync. They must not differ.There seems to be some confusion what role the
elementhas inelement.matchContainer(...)so let me try to clarify: theelementis the descendant, not the container. An eligible container is searched in the ancestor chain of that element; when a container is found that is eligible (its container-type corresponds to the query type, container-name matches if one is required by the query) the condition is checked, and if met, the query reportsmatchesastrue. This meanselementis currently in a container that fulfills the query condition.@jamesnw My polyfill does not enforce or assume any descendant and ancestor relationship for the watched element; so for the unlikely case that one day a container query type should be added to the CSS standard that would allow an element to form its own container, then this should just work fine through the polyfill.
You contributed a testcase to the polyfill recently; so I believe I know your use case for needing to match an
anchoredquery for a custom styled<select>element. You don't need to pick the first<option>to get a reference to a descendant, you can use the dropdown element itself and it doesn't feel hacky anymore. It seems when aselectis set toappearance: base-selecti.e. custom styled the browser provides a popover that acts as a container, having<div class="dropdown">(or whatever you put as content) as its child.Loirooriol commentedon Mar 9, 2026
Yeah,
iframe.matchMedia()checks the parent document, not the nested one. So here it's the same.Also, consider
@container (width > 30em), (height > 40em):widthandheightcan even query different containers. So it's not clear what this means if the context element was supposed to be "the" container, especially if if only contains in one or zero axes.For observing the element itself, better use
ResizeObserverinstead, and if needed for style queries or such, consider new observers in different issues (e.g.ComputedStyleObserverin #8982)jamesnw commentedon Mar 9, 2026
That doesn't seem to work in my testing, but was the first thing I tried. Even then, in that example the container itself is set on the
::picker()pseudoelement, notdiv.dropdown.I'd imagine a
matchSelfAsContainer()(bikeshed) function would check if the element itself is an established container matching that. So If it has height and width, but only hascontainer: inline-size, it would throw.Then, a
matchInsideContainer()function would check if the element is inside a matching container. I think there's probably need for both.I suspect that anchored container queries would mostly use
matchSelfAsContainer(), as it is more about state than context, and other queries would mostly usematchInsideQuery().DevSDK commentedon Mar 12, 2026
Ah, thanks for clarifying that, everyone.
According to the css-conditional-5, it describes about figuring out the container from the ancestor.
I initially thought this api is likely
matchSelfAsContainer. Maybe it is good to mention this on the spec.FWIW, If we need like
matchSelfAsContainermaybe, we can remove the word container from the API and probably this off the topic.DevSDK commentedon Sep 30, 2026
Originally posted by @emilio in #13551 (comment)
#13551 adds
matchContainer()without thechangeevent, so we still need to decide how authors observe changes, which the resolution left open. Options I see:changeevent onContainerQueryList, matchingmatchMedia(). The dropped spec text is in 1d44ed7, and loop termination is tracked in [css-conditional-5] Element.matchContainer has no termination rule for change event listeners #14430. Chromium has a prototype behind--enable-blink-features=ElementMatchContainerif anyone wants to try it, and there's a tentative WPT.style()andscroll-state()changes, which can flip without a resize.Thoughts?