Media Queries and Breakpoints

In order to make it as declarative and easy to handle media queries from JavaScript, you may be interested to use both the MediaQuery React component and the useMediaQuery React hook.

Media Queries Properties Table

UX designers are using a 12 column system during their design processes.

PixelTypeRemCustom PropertyComments
640small40em--layout-smallMobile
800medium50em--layout-medium
960large60em--layout-largeDNB default
1152x-large72em--layout-x-large
1280xx-large80em--layout-xx-large

MediaQuery component and the useMediaQuery hook

Both the component and the hook uses the JavaScript API matchMedia.

Re-render and performance

By using matchMedia we only render when the requested media query actually changes. So we do not need to listen to e.g. window.addEventListener('resize', ...) which is a performance waste, even with a debounce helper.

CSS similarity

It uses the same query API as CSS uses. You are able to provide your query also raw, by using e.g. query="(min-width: 50em)". But your custom queries will quickly grow and mess up your application code unnecessarily.

Properties

You can both use min and max, they are equivalent to minWidth and maxWidth.

CamelCase properties will be converted to kebab-case.

SSR

During a SSR (Server Side Render) we do not have the clients window.matchMedia. In order to make the initial render to a positive match, you can set the ssr={true} property.

Units

Numeric values will be handled as an em unit.

MediaQuery usage

import { MediaQuery } from '@dnb/eufemia/shared'
// or
import MediaQuery from '@dnb/eufemia/shared/MediaQuery'

You have plenty of possibilities to mix and match:

<MediaQuery when={{ min: 'medium' }}>
matches all above medium screens
</MediaQuery>
<MediaQuery when={{ screen: true, orientation: 'landscape' }}>
matches orientation landscape screens
</MediaQuery>
<MediaQuery not when={{ min: 'large' }}>
matches all, but beneath large screens
</MediaQuery>
<MediaQuery ssr when={{ min: 'small', max: 'medium' }}>
matches small and medium screens and during SSR
</MediaQuery>
<MediaQuery when={[{ min: 'small', max: 'x-large' }, { print: true }]}>
matches all between small and x-large screens or all print media
</MediaQuery>
<MediaQuery when={{ max: '80em' }}>
matches screens to a max of 80em
</MediaQuery>
<MediaQuery query="(min-width: 40em) and (max-width: 72em)">
matches screens between 40em and 72em
</MediaQuery>

You find the properties on this page.

Interceptor on change listener

import { onMediaQueryChange } from '@dnb/eufemia/shared/MediaQuery'
const remove = onMediaQueryChange({ min: 'medium' }, (match, event) => {
// callback
})
// Will remove the listeners
remove()

useMediaQuery hook usage

import { useMediaQuery } from '@dnb/eufemia/shared'
// or
import useMediaQuery from '@dnb/eufemia/shared/useMediaQuery'
function Component() {
const match = useMediaQuery({
ssr: true,
when: { min: 'medium' },
})
return match ? 'true' : 'false'
}

Live example

This example uses the not property to reverse the behavior.

Use different breakpoints

It is possible to change the used breakpoint types by providing them to the Eufemia Provider.

Both the MediaQuery component and the useMediaQuery hook will merge and use these custom breakpoints.

import { Provider } from '@dnb/eufemia/shared'
...
<Provider
value={{
breakpoints: {
xsmall: '20em',
medium: '30em',
large: '60em',
},
}}
>
...
<MediaQuery when={{ min: 'xsmall' }}>
matches all above xsmall screens
</MediaQuery>
...
</Provider>

Import breakpoints into JavaScript

You get an object with the values and the types as the keys.

import { defaultBreakpoints } from '@dnb/eufemia/shared/MediaQueryUtils'

SASS / SCSS mixins

You can re-use the SASS mixins from Eufemia:

@import '@dnb/eufemia/style/core/utilities.scss';
@include allBelow(large) {
/* Your CSS */
}
@include allAbove(small) {
/* Your CSS */
}

Media Queries Examples

@media screen and (max-width: 40em) {
/* small (mobile) */
}
@media screen and (max-width: 50em) {
/* medium */
}
@media screen and (max-width: 60em) {
/* large (default) */
}
@media screen and (min-width: 60em) and (max-width: 72em) {
/* x-large */
}
@media screen and (min-width: 70em) and (max-width: 80em) {
/* xx-large */
}

Based of the findings of this article and this webkit bug Eufemia recommends to use em units for media query usage to meed the best overall browser support. Read more about units.