Open scherroman opened 2 years ago
Dug around some more and found the Display page of MUI System which recommends using the sx
breakpoints to hide and show elements at different screen sizes using the display
property. Makes sense and works well! Also would work better than a hook if using server-side rendering. Though if you use display: block
to show buttons it messes up their styling. Tried to just omit the breakpoints where the component is visible as it's redundant, but that causes the button not to show, so had to look in the browser console to find that normally display: inline-flex
is used and explicitly use that. Would be nice to have a way to just use the default or set display
to 'whatever the value should be/would have been if I wasn't setting it'
<IconButton
sx={{
display: { mobile: 'none', tablet: 'inline-flex' }
}}
>
<SettingsIcon />
</IconButton>
<Button
startDecorator={<SettingsIcon />}
sx={{
display: { mobile: 'inline-flex', tablet: 'none' }
}}
>
Settings
</Button>
Reopening this as I've run into a situation where I want to adapt a modal from layout='fullscreen'
when on mobile to layout='center'
when on tablet or larger, which is not covered by the use of breakpoints on the sx
property. Passing in an object with breakpoints like <ModalDialog layout={{ mobile: 'fullscreen', tablet: 'center' }}>
doesn't appear to work either.
It seems the useMediaQuery
hook is needed to support this. In the meantime, I've gotten around this by using the useMedia hook from react-use:
import { useMedia } from 'react-use'
import {
Modal,
ModalDialog,
useTheme
} from '@mui/joy'
const EditModal = () => {
let theme = useTheme()
let isMobile = useMedia(`(max-width: ${theme.breakpoints.values.tablet}px)`)
return (
<Modal open onClose={onClose}>
<ModalDialog layout={isMobile ? 'fullscreen' : 'center'}>
</ModalDialog>
</Modal>
)
}
Honestly, I don't recommend using JS to switch between layouts. Always use CSS if you can.
This is better for sure:
<Modal open onClose={onClose}>
<ModalDialog layout="center" sx={theme => ({
[theme.breakpoints.only('xs')]: {
top: 0,
left: 0,
right: 0,
bottom: 0,
border: 0,
borderRadius: 0,
transform: 'initial',
}
})}>
</ModalDialog>
</Modal>
I am changing this issue to a question instead.
After reading the original issue, it is not about the Modal. I will try to add some docs about the media query to Joy UI.
Honestly, I don't recommend using JS to switch between layouts. Always use CSS if you can.
This is better for sure:
<Modal open onClose={onClose}> <ModalDialog layout="center" sx={theme => ({ [theme.breakpoints.only('xs')]: { top: 0, left: 0, right: 0, bottom: 0, border: 0, borderRadius: 0, transform: 'initial', } })}> </ModalDialog> </Modal>
Thanks for showing that! Though are there any reasons to prefer using css over js aside from css better supporting server-side rendering? It does seem like a lost opportunity to have to directly override all the styles already applied by a property like layout
to replicate a different layout at certain breakpoints, instead of being able to simply change the value of the property itself with something like layout={{ mobile: 'fullscreen', tablet: 'center' }}
or some similar way.
Though are there any reasons to prefer using css over js aside from css better supporting server-side rendering?
I think CSS is simpler, and framework agnostic. This is just one small example but in a production app, the more JS you have the more complexity you have to handle as well.
layout={{ mobile: 'fullscreen', tablet: 'center' }}
I have been thinking about providing style utilities in Joy UI to make it easier for developers in situations like this:
import ModalDialog, { getLayoutFullscreenStyle } from '@mui/joy/ModalDialog';
<ModalDialog
layout="center"
sx={theme => ({
[theme.breakpoints.only('xs')]: getLayoutFullscreenStyle(),
})}
/>
I think this will benefit the developer's productivity and allows us to create tailor-made styles that won't impact production bundle size if you don't use them.
What do you think?
I have been thinking about providing style utilities in Joy UI to make it easier for developers in situations like this:
import ModalDialog, { getLayoutFullscreenStyle } from '@mui/joy/ModalDialog'; <ModalDialog layout="center" sx={theme => ({ [theme.breakpoints.only('xs')]: getLayoutFullscreenStyle(), })} />
I think this will benefit the developer's productivity and allows us to create tailor-made styles that won't impact production bundle size if you don't use them.
That would be a big improvement over having to manually specify the styles as it's simpler, clearer, and less mental overhead/error-prone in determining which styles to override.
Personally however I love the simplicity, conciseness, and explicitness of being able to optionally pass in an object with breakpoints to properties the most, similar to how the Stack and Grid components from MUI System allow for some properties:
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 1, sm: 2, md: 4 }}>
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
Not sure if this is more difficult to achieve for higher-level properties, or about its impact on bundle size and the best way to optimize there, but my biggest consideration would be for the fluidity and expressiveness of the API. Perhaps the two methods are not mutually exclusive
I'm trying to render a table with fewer columns on smaller screens and I can't set colSpan
dynamically with css/sx, so I need useMediaQuery
or to not use a table. Joy supports <Table>
with native <td>
/ <th>
, so I think it could make sense to add this feature as well.
Is there any progress on this? It would be great if hooks like these aren't specific to Material (or Joy for that matter). So far all use cases mention here have been related to width/height/dimensions, but I personally also have various use-cases for this hook that depend on capabilities of hover, the pointer type, whether or not its a screen, etc.
Another use case where at least I can not make use of the sx
prop is the Drawer component. I have a need to be able to anchor the drawer to the left side of the screen on desktop but to the right side on mobile. I can not see a easy way of doing that without giving the Drawer component different values of the the anchor
prop.
The useMediaQuery
can be moved to @mui/system
to be shared across Material UI and Joy UI.
Does anyone want to take this?
@siriwatknp I can try!
I'm thinking move the hook into@mui/system
then re-export it from @mui/material
to prevent breaking changes.
Can we not use the useMediaQuery hook from @mui/material using experimental_extendTheme?
Create your own hook
import { useEffect, useState } from 'react'
const useMediaQuery = query => {
const [matches, setMatches] = useState(false)
useEffect(() => {
const mediaQuery = window.matchMedia(query)
setMatches(mediaQuery.matches)
const handler = event => setMatches(event.matches)
mediaQuery.addEventListener('change', handler)
return () => mediaQuery.removeEventListener('change', handler)
}, [query])
return matches
}
export default useMediaQuery
In a file
import useMediaQuery from 'somewhere/in/your/project/useMediaQuery';
const isMdOrSmaller = useMediaQuery('(max-width: 900px)')
console.log('isMdOrSmaller', isMdOrSmaller)
Duplicates
Latest version
Summary 💡
I'd like to be able to import and use
useMediaQuery
with Joy UI just like Material UI supports to adapt my layout for different screen sizesExamples 🌈
Motivation 🔦
I'm trying to adapt my interface to have my navigation bar show just an
IconButton
when on a tablet or larger sized screen, but a larger regularButton
with an icon when on a mobile sized screen. At the moment I appear to be unable to do so without something likeuseMediaQuery
which has access to my theme's media breakpoints, which makes the app less friendly and functional on mobile. While thesx
prop is very useful for adapting individual components, it's common to want to render entirely different components at different breakpoints.For reference, my breakpoints are set to:
Many well-designed web apps like Twitter have elements like side bars that collapse, disappear completely (like the "What's happening" bar on the righthand side) or are replaced by new layouts (like the navigation bar on the lefthand side, which collapses at smaller sizes and is wholly replaced by a bottom navigation bar on mobile). This kind of adaptability is essential for designing a responsive/mobile-friendly app.
If there's a workaround in the meantime I'd be happy to learn it! I love the aesthetic of Joy UI much more than Material UI 2, so am eager and making an effort to use it although it's still in alpha.