Let Me Tink About It
Let Me Tink About It

Reputation: 16132

Media query syntax for Reactjs

How do I do the following CSS media query in Reactjs?

.heading {
  text-align: right;
  /* media queries */
  @media (max-width: 767px) {
    text-align: center;
  }
  @media (max-width: 400px) {
    text-align: left;
  }
}

I tried the following but it throws a syntax error and fails to compile.

heading: {
  textAlign: 'right',
  @media (maxWidth: '767px') {
    textAlign: 'center';
  }
  @media (maxWidth: '400px') {
    textAlign: 'left';
  }
}

Upvotes: 52

Views: 202096

Answers (16)

Al Vedder
Al Vedder

Reputation: 107

I ended up with the following solution, similar to Muhammed Moussa's one but with no external libraries:

export default function App() {
  const yourCss = `
    .heading {
       text-align: right;
       /* media queries */
       @media (max-width: 767px) {
         text-align: center;
       }
       @media (max-width: 400px) {
         text-align: left;
       }
    }`;

  return (
    <>
      <style>{yourCss}</style>
      <h1 className="heading">
        Styled heading
      </h1>
    </>
  );
}

Upvotes: 0

tao
tao

Reputation: 90277

import { useResponsiveness } from "react-responsiveness";

const { isMax } = useResponsiveness()
// also available: { isMin, isOnly, currentInterval, matches } 
// ...

  heading: {
    textAlign: isMax('sm') 
      ? 'left'
      : isMax('md')
      ? 'center'
      : 'right'
  }
// provider in App.(js|ts):

import { ResponsivenessProvider } from "react-responsiveness";

const breakpoints: {
  sm: 0,
  md: 401,
  lg: 768
}

function App() {
    // ...
}

const ResponsiveApp = () => (
  <ResponsivenessProvider {...{ breakpoints }}>
    <App />
  </ResponsivenessProvider>
);

export default ResponsiveApp;

Documentation and more examples.

Note: I wrote this package myself, because others were adding a set of listeners for each component needing a media query, instead of adding them only once per app, which is best practice (I'm obsessed with runtime performance and user experience).

Upvotes: 2

Ferit
Ferit

Reputation: 9727

You can make media queries inside React:

import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = { matches: window.matchMedia("(min-width: 768px)").matches };
  }

  componentDidMount() {
    const handler = e => this.setState({matches: e.matches});
    window.matchMedia("(min-width: 768px)").addEventListener('change', handler);
  }
  render() {
    return (
      <div >
      {this.state.matches && (<h1>Big Screen</h1>)}
      {!this.state.matches && (<h3>Small Screen</h3>)}
      </div>
    );
  }
}

export default App;

https://stackblitz.com/edit/react-cu8xqj?file=src/App.js

Upvotes: 53

Adioz Daniel
Adioz Daniel

Reputation: 516

If you don't want many complications put the class itself inside the media query and only change whatever should change at that particular query:

.heading {
   text-align: right;
   width: 360px;
   height: fit-content;
   padding: 10px 0px;
   box-shadow: 1px 3px 2px 0px rgb(206, 117, 1);
   display: flex;


/* media queries */

@media (max-width: 767px) {
.heading{
   text-align: center;
}
}

@media (max-width: 400px) {    
.heading{
   text-align: left;
}
}

Upvotes: 0

Francesco Orsi
Francesco Orsi

Reputation: 2089

you can just make your own custom hook like this working snippet of code

hooks/useStyleMediaQuery.js

import { useState, useEffect } from 'react'

export const useStyleMediaQuery = ({ mixOrMax, widthOrHeight, value }) => {

  if (!mixOrMax) mixOrMax = 'min';
  if (!widthOrHeight) widthOrHeight = 'width';

  const [matches, setMatches] = useState(
    window.matchMedia(`(${mixOrMax}-${widthOrHeight}: ${value}px)`).matches
  )

  useEffect(() => {
    window
      .matchMedia(`(${mixOrMax}-${widthOrHeight}: ${value}px)`)
      .addEventListener('change', e => setMatches(e.matches));
  }, [mixOrMax, widthOrHeight, value]);

  return { matches }

}

App.js

import { useStyleMediaQuery } from 'hooks/useStyleMediaQuery'

import ComponentIwantToShowOnlyOnMobile from 'components/ComponentIwantToShowOnlyOnMobile'
import ComponentIwantToShowOnlyOnDesktop from 'components/ComponentIwantToShowOnlyOnDesktop'

function App() {

    const { matches: isMobile } = useStyleMediaQuery({ mixOrMax: 'max', widthOrHeight: 'width', value: 767 });
    const { matches: imSmall } = useStyleMediaQuery({ mixOrMax: 'max', widthOrHeight: 'width', value: 400 });

    return (
        <>
            {isMobile && <ComponentIwantToShowOnlyOnMobile />}
            {!isMobile && <ComponentIwantToShowOnlyOnDesktop />}
            {imSmall && <h1>I'm very small.. 400px width or less</h1>}
        </>
    );
}

export default App;

that's it :)

Upvotes: 2

user19693683
user19693683

Reputation: 21

JSX or reactJS indicatorContainerProps:{ position: 'fixed', right: '0px', bottom: '0%', marginBottom: '40%', display:'flex', justifyContent:'center', flexDirection:'row', alignItems:'center', "@media (orientation:landscape)": { marginBottom: '0px' }

Upvotes: 1

Kirill Kovalevskiy
Kirill Kovalevskiy

Reputation: 2002

Drop in no dependencies hook solution. Works with server side rendered Nextjs.

const useQuery = (query: string) => {
  const [matches, setMatches] = useState(false)

  const handleChange = (e) => setMatches( e.matches )

  useEffect(() => {
    const m = window.matchMedia(query)

    setMatches(m.matches)
    
    m.addEventListener('change', handleChange);

    return () => {
      m.removeEventListener('change', handleChange);
    }
  }, []);

  return !matches;
}

const Menu= () => {
  const isMobile = useQuery("(min-width: 768px)");
  ...
}

Upvotes: 3

YassBan
YassBan

Reputation: 91

const styles = (window.innerWidth > window.innerHeight) ? {
    header: {
        display: 'flex',
        justifyContent: 'center',
    },
    body: {
        boxShadow: '0px 0px 5px black',
        display: 'flex',
        justifyContent: 'center',
        flexDirection: 'column'
    }
} : {
    // other styles
}

You can use this syntax for your styles.

Upvotes: 0

Marcos Guerrero
Marcos Guerrero

Reputation: 398

The answer given by Ferit turned out to be quite useful, however, it was only the example in class components, but it is usually difficult or cumbersome to apply that to functional components, and since sometimes it is problematic to transform a functional component to a class one, here I leave the example using Hooks

import React, { useState, useEffect } from 'react';

const App = () => {
  const [matches, setMatches] = useState(
    window.matchMedia("(min-width: 768px)").matches
  )

  useEffect(() => {
    window
    .matchMedia("(min-width: 768px)")
    .addEventListener('change', e => setMatches( e.matches ));
  }, []);

  return (
    <div >
      {matches && (<h1>Big Screen</h1>)}
      {!matches && (<h3>Small Screen</h3>)}
    </div>
  );
}

export default App;

Upvotes: 34

Nikhil Gowda
Nikhil Gowda

Reputation: 457

Another way of writing media query in reactjs project:

style.js file:

root: {
 background: "white",

 "@media (max-width: 1920px)": {
   background: "red",
 }
}

style.css file:

.root: {
 background: "white";

 @media (max-width: 1920px) {
   background: "red";
 }
}

Thank you

Upvotes: 13

Muhammed Moussa
Muhammed Moussa

Reputation: 5205

aphrodite can help.

here is an example:

import React from "react";
import { StyleSheet, css } from "aphrodite";

import "./style.css";

const styles = StyleSheet.create({
  heading: {
    textAlign: "right",
    backgroundColor: "red",
    "@media (max-width: 767px)": {
      textAlign: "center",
      backgroundColor: "green"
    },
    "@media (max-width: 767px)": {
      textAlign: "center",
      backgroundColor: "blue"
    }
  }
});

export default function App() {
  return (
    <div className={css(styles.heading)}>
      <h1>Hello aphrodite!</h1>
    </div>
  );
}

Upvotes: 1

Imriven
Imriven

Reputation: 141

You can use styled-components if you're used to using css. It would look something like this.

import React from 'react';
import Styled from "styled-components";

function YourComponent() {

    const heading = Styled.h1`
        Text-align:right;

            @media (max-width: 767px) {
                text-align: center;
            }
            @media (max-width: 400px) {
                text-align: left;
            }
    `;

   return(
        <>
           <heading>This is my heading</heading>
        </>
    )
}

If you have a lot of styling you need to do you can do your styles in another js file and import each style as needed. If you do this don't forget to export your style.

Upvotes: 10

Josh Pittman
Josh Pittman

Reputation: 7324

You cannot set media queries inline. You will need to create a separate CSS stylesheet and then import the stylesheet.

So the following code would go in a new styles.css file for example.

.heading {
  text-align: right;
  /* media queries */
  @media (max-width: 767px) {
    text-align: center;
  }
  @media (max-width: 400px) {
    text-align: left;
  }
}

Then you can import your new CSS styles file into your react file. For example, you could add import './styles.css' to the top of your App.jsx file (assuming they are both at the root level), or you could import it directly into a specific react component file.

Upvotes: 20

amdev
amdev

Reputation: 7460

in my case i was using a custom hook to generate some breakpoint values for me:

import { useMediaQuery } from 'react-responsive';

export const useBreakpoints = () => {
  const isMobileSmall = useMediaQuery({ query: '(max-width: 325px)' });
  const isMobileMid = useMediaQuery({ query: '(max-width: 375px)' });
  const isMobileFloor = useMediaQuery({ query: '(max-width: 425px)' });

  const isTabletFloor = useMediaQuery({ query: '(max-width: 426px)' });
  const isTabletMid = useMediaQuery({ query: '(max-width: 768px)' });
  const isTabletCeil = useMediaQuery({ query: '(max-width: 1024px)' });

  const isLaptopFloor = useMediaQuery({ query: '(max-width: 1025px)' });
  const isLaptopCeil = useMediaQuery({ query: '(max-width: 1440px)' });

  const isXHDFloor = useMediaQuery({ query: '(max-width: 1441px)' });
  const isXHDCeil = useMediaQuery({ query: '(max-width: 4096px)' });

  return {
    isMobileSmall,
    isMobileMid,
    isMobileFloor,
    isTabletFloor,
    isTabletMid,
    isTabletCeil,
    isLaptopFloor,
    isLaptopCeil,
    isXHDFloor,
    isXHDCeil,
  };
};

and i was calling it in my component inside of useMemo, which is incorrect :)

so i put it outside of useMemo and it worked as charm!

basically what i'm trying to point you at is avoid using nested hook call!

Upvotes: 2

Harjaap Dhillon
Harjaap Dhillon

Reputation: 21

there is also a way to include a media query by using boolean values for ex.

<div style={{window.innerWidth > 768 ? '800px' : '400px'}}/>

and this serves the problem well

Upvotes: 1

Ilya Lesik
Ilya Lesik

Reputation: 264

If you have a special cases, when you need to get media query result inside you react app (for example, you want to show some component at mobile version), you can use helpers like react-responsive or react-media-hook.

Upvotes: 22

Related Questions