Handle media queries in a type-safe way using TypeScript
Karibash
Posted on September 25, 2021
I’ve created a library that can execute media queries in a type-safe way with TypeScript.
If you find it useful, I’d appreciate it if you’d give it a star in the repository.
Install
with emotion
npm install @medi-q/core @medi-q/react @medi-q/emotion
with styled-components
npm install @medi-q/core @medi-q/react @medi-q/styled
Usage
Use the MediQProvider component to pass mediQ objects to lower-level components.
Also, only valid units can be specified for BreakPoints, and a type definition error will occur if an invalid unit is entered.
import React from 'react';
import { BreakPoints, createMediQ } from '@medi-q/core';
import { MediQProvider } from '@medi-q/react';
const breakPoints: BreakPoints = {
tiny: '400px',
small: '600px',
medium: '800px',
large: '1000px',
};
const App: React.FC = () => {
return (
<MediQProvider mediQ={createMediQ(breakPoints)}>
...
</MediQProvider>
);
};
export default App;
By using the useMediQ hook in the lower-level component, you can execute a media query.
Since the arguments of useMediQ hooks are typed to accept only valid values, a typedef error will occur if an invalid value is entered.
You can also execute media queries with multiple conditions by connecting the queries with and or.
import React from 'react';
import { useMediQ } from '@medi-q/react';
const Page: React.FC = () => {
const isLessThanSmall = useMediQ('max-small');
const isGreaterThanMedium = useMediQ('min-medium');
const isBetweenSmallAndMedium = useMediQ('min-small-and-max-medium');
return (
<div>
{isLessThanSmall && <div>isLessThanSmall</div>}
{isGreaterThanMedium && <div>isGreaterThanMedium</div>}
{isBetweenSmallAndMedium && <div>isBetweenSmallAndMedium</div>}
</div>
);
};
export default Page;
CSS in JS
For use with styled-components and emotion, use medi-q ThemeProvider.
import React from 'react';
import { BreakPoints, createMediQ } from '@medi-q/core';
import { ThemeProvider } from '@medi-q/emotion';
// import { ThemeProvider } from '@medi-q/styled';
import theme from './theme';
const breakPoints: BreakPoints = {
tiny: '400px',
small: '600px',
medium: '800px',
large: '1000px',
};
const App: React.FC = () => {
return (
<ThemeProvider theme={theme} mediQ={createMediQ(breakPoints)}>
...
</ThemeProvider>
);
};
export default App;
You can use medi-q via theme in styled components as follows.
import React from 'react';
import styled from '@emotion/styled';
// import styled from 'styled-components';
import { useMediQ } from '@medi-q/react';
const Wrapper = styled.div`
background: ${props => props.theme.background};
${props => props.theme.mediQ('max-medium')} {
background: blue;
}
`;
const Page: React.FC = () => {
const isLessThanSmall = useMediQ('max-small');
const isGreaterThanMedium = useMediQ('min-medium');
const isBetweenSmallAndMedium = useMediQ('min-small-and-max-medium');
return (
<Wrapper>
{isLessThanSmall && <div>isLessThanSmall</div>}
{isGreaterThanMedium && <div>isGreaterThanMedium</div>}
{isBetweenSmallAndMedium && <div>isBetweenSmallAndMedium</div>}
</Wrapper>
);
};
export default Page;
When medi-q is used in styled components, it will be converted as follows.
const Wrapper = styled.div`
background: ${props => props.theme.background};
${props => props.theme.mediQ('max-medium')} {
background: blue;
}
`;
↓
const Wrapper = styled.div`
background: ${props => props.theme.background};
@media (max-width: 50rem) {
background: blue;
}
`;
Posted on September 25, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.