Make container queries that harness the power of Ember Octane.
Open the demo app to see ember-container-query
in action. (There's even a 404 page!)
ember install ember-container-query
Use FastBoot? ⚠️
This addon uses nullish coalescing operator ??
. If you use FastBoot (with Node < v14.0
) and only support browsers that natively support ??
, you will run into a build error:
/var/folders/2z/93zyyhx13rs879qr8rzyxrb40000gn/T/broccoli-689520dxo26a682Mz/out-529-broccoli_merge_trees/assets/vendor.js:121232
return this.args.features ?? {};
^
SyntaxError: Unexpected token '?'
To prevent this, please make sure to add node: 'current'
to your config/targets.js
file.
'use strict';
const browsers = [ ... ];
module.exports = {
browsers,
node: 'current'
};
Where can you use container queries? Here are real-life (and some theoretical) applications!
Create reusable components that are independent of screen size ♻️
-
Components form a core of an Ember app. We love components!
-
With media queries,
-
A design that looked amazing on 2 or 3 fixed screen sizes can end up looking terrible at a size in-between.
-
Designing the template for specific screen sizes isn't a future-proof solution. You may need to reuse the component under different local width and height constraints.
-
In
ember-qunit
tests, the window is scaled by default. You may end up stubbing a service (fake the window size) to get certain DOM elements to (dis)appear.
-
-
With container queries,
-
A component only needs to know how much space it has to figure out how to best present data.
-
Since each component can be free to decide how it looks, a webpage may end up with an unexpected combined look. This may be good, may be bad.
-
In tests, you will be driven to have a correct window size. If the window size is correct, then all elements should (dis)appear just like they would on your browser.
-
To table or not to table? That is the question. 🤔
-
A table is great for showing structured data. On mobile, with a limited width, not so much.
-
You can use a list to show data vertically. This works until the user rotates the screen and sees only so much at a time.
-
You can use container queries to decide which table columns to show and how many columns to spread the list across.
Create a customizable dashboard 🎛️ 🎚️
-
It's difficult to create dashboard widgets that can be placed anywhere and look good.
-
As a result, you may artificially constrain your users from customizing their dashboard.
-
If you combine media and container queries, you can better meet the wants of designers, developers, and users.
Responsive images, videos, and D3 visualizations 🖼️ 📽️ 📈
-
Currently, you have to use
srcset
to load images with the optimal file size. Alternatively, you can use container queries to decide which images to load. -
Similarly, for videos, you could use container queries to decide format and display resolution.
-
D3 components can use container queries to decide what's the best way to show data. Do you show larger chart elements, show legends, allow scrolling, show text summary? etc.
Create beautiful, printable pages 🖨️
-
You may be able to compose this addon with others to arrive at something ambitious and unique.
-
For example,
ember-printable-pages
lets us reuse components to make a printable document. The components could focus on presenting data with container queries, whileember-printable-pages
could focus on deciding page layouts and lazily rendering components.
Hide secrets in games 🎮
-
You're designing a game in Ember.
-
Maybe a secret, most powerful item appears when the game world is at a certain size? :)
The addon provides 1 Glimmer component and 3 helpers:
<ContainerQuery>
{{cq-aspect-ratio}}
{{cq-height}}
{{cq-width}}
<ContainerQuery>
You can pass these arguments to the component.
Name | Required | Description | Type |
---|---|---|---|
@features | Yes1 | Container query definitions | POJO |
@dataAttributePrefix | No | Prefix for data attributes | string |
@debounce | No | Debounce time for resize (ms) | number ≥ 0 |
@tagName | No | Container tag name2 | HTML tag name |
1. The component renders without error when @features
isn't provided. In practice, you will always want to set @features
.
2. By default, the component is a <div>
element. You can pass a valid HTML tag name to facilitate accessibility and semantic HTML.
You may1 pass attributes to the component for these reasons:
- Style (e.g.
class
,local-class
) - Accessibility (e.g. ARIA attributes2, roles)
1. Do refrain from overusing splattributes (e.g. pass a {{did-insert}}
modifier to fetch data), since the component's API may change and cause unexpected results. Practice separation of concerns when possible. For example, data fetching can be handled by another element or @use
decorator.
2. When an ARIA attribute has multiple values, the order of values can matter. At the moment, splattributes doesn't guarantee the order.
You can consume these values in your app or addon.
Name | Yielded | Description | Type |
---|---|---|---|
features | Yes | Container query results | POJO |
dimensions | Yes | Container dimensions | POJO |
data-container-query-{featureName} | No | Data attributes for CSS selector | HTML data attribute |
{{cq-aspect-ratio}}
, {{cq-height}}
, {{cq-width}}
All helpers accept these arguments:
Name | Required | Description | Type |
---|---|---|---|
min | Yes1 | Lower bound for feature2 | number ≥ 0 |
max | Yes1 | Upper bound for feature2 | number ≥ 0 |
1. The helpers use default values of min = 0
and max = Infinity
, and assume the inequalities min ≤ x < max
. In practice, you will always want to set min
or max
(or both).
2. Aspect ratio is unitless. Height and width have the unit of pixel.
Let's look at the code that created the video demo above.
app/templates/album.hbs
app/components/tracks.hbs
You can see that the album page uses 2 <ContainerQuery>
components. Rest assured, they act independently of each other. When you pair <ContainerQuery>
with some CSS, you can create layouts beyond the dreams of others! 🙌
For more examples, I encourage you to check out the code for my demo app. It is located under tests/dummy/app
folder and is structured like a typical Ember app.
- Ember.js v3.24 or above1
- Ember CLI v3.24 or above
- Node.js v12 or above
- Modern browsers1 (IE 11 won't be supported)
1. Until you can adopt Ember Octane and drop support for IE 11, I recommend using ember-fill-up
to do container queries. The APIs are similar so your migration should be smooth. Chad Carbert and I will ensure that the addons are maintained side-by-side for some time.
See the Contributing guide for details.
Much thanks goes to Chad Carbert (@chadian), who introduced me to container queries at EmberFest 2019 and created ember-fill-up
🌟. I modeled the API for ember-container-query
based on Chad's addon.
This project is licensed under the MIT License.