Material UI - center an element vertically inside FlexBox - css

In my react app I created a card with min width and height and it contains only a header. I would like to add a flexbox which would take the whole left space with justify-content="center" and align-items="center" so when I add a circular progress element it will be in the middle of the card. Unforunately whatever I do the flexbox's height equals the loading spinner height and it does not take the whole space. How to fix it?
My Component:
function AccountSettings({isLoading, id, username, isDisable}) {
const classes = useStyles();
return (
<Card
className={classes.accountSettings}
>
<CardHeader
title="Something"
/>
<Divider/>
<Box
display="flex"
alignItems="center"
justifyContent="center"
height={"100%"}
width={"100%"}
>
<CircularProgress/>
</Box>
</Card>
);
}
My style:
import {makeStyles} from "#material-ui/styles";
export default makeStyles(theme => ({
root: {
maxWidth: "1000px"
},
pageTitle: {
padding: "5px"
},
accountSettings: {
minWidth: "312px",
minHeight: "273px",
}
}));
And here my main view:
<div className={classes.root}>
<AccountSettings/>
</div>
This image shows my issue

Here is one solution
Add the following to the styles:
accountSettings: {
display: 'flex',
flexDirection: 'column'
},
box: {
flexGrow: 1
}
And add the class to the Box element:
<Box
className={classes.box}

Related

How to make border around material ui grid items only

import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
container: {
border: '4px solid green',
display: 'inline-flex',
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
}));
export default function CenteredGrid() {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid container justify="center" className={classes.container}>
<Grid item xs={4}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
</Grid>
</div>
);
}
I'd like my border to be around only the two items in the Grid container. Currently the border takes up the full width of the container. Even after adding inline-flex to parent container, it doesn't change the border taking full width.
You just to create in your function useStyle, on the return object :
container: {
border: '4px solid green',
display: 'inline-flex',
},
item: {borderRadius: 30px},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
and put :
<Grid item xs={4} classeName={classes.item}>
It's simple so I have a doubt about my capacity to understand your problem, if, please comment.

Material-ui Grid: Grid item's width too big and going outside of Grid container

I am trying to set up a simple layout for a SPA using Material-ui and React. My idea is to have a left hand column as a sidebar and a right-hand main area to render information etc. However, in my current set-up I have two issues:
The <Grid item> and its container <Button> elements extend beyond the left sidebard <Grid container item xs={3} className={classes.sideBarGrid}> into the right hand column. I am not sure what I am doing wrong and any help would be greatly appreciated!
Code Sandbox
Also, I cannot get the right hand grid column <Grid container item xs={9} className={classes.labelGrid}> get to work to be full width, even though I set it to width: "100%".
Code:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import CssBaseline from "#material-ui/core/CssBaseline";
import Typography from "#material-ui/core/Typography";
import Grid from "#material-ui/core/Grid";
import Button from "#material-ui/core/Button";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
mainContainer: {
width: "100vw",
height: "100vh"
},
labelGrid: {
flexGrow: 1,
flexDirection: "column",
backgroundColor: "#EBEDF0",
alignItems: "center",
justifyContent: "center",
width: "100%"
},
sideBarGrid: {
maxWidth: 300,
flexDirection: "column",
justifyContent: "space-between"
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
labelarea: {
margin: theme.spacing(1)
},
imagearea: {
minHeight: 200
},
classButton: {
margin: theme.spacing(1)
},
submit: {
margin: theme.spacing(1)
},
commentField: {
margin: theme.spacing(2, 2, 3)
}
}));
export default function Labelscreen(props) {
const classes = useStyles();
// history for react router
// array with potential classes for image
const buttonText = ["one", "two"];
// function to filter list of labels by property and see if object property is null
return (
<Grid container className={classes.mainContainer}>
<CssBaseline />
<Grid container item xs={3} className={classes.sideBarGrid}>
<Grid item>
{buttonText.map((item, key) => (
<Button
className={classes.classButton}
variant="outlined"
color="primary"
fullWidth
>
{item} ({key + 1})
</Button>
))}
<TextField
id="imageComment"
label="Comment"
placeholder="please put comments here"
multiline
fullWidth
variant="outlined"
value="adfljdaf"
/>
</Grid>
<Grid item>
<Button
type="submit"
fullWidth
variant="contained"
color="secondary"
className={classes.submit}
>
Go back
</Button>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Next
</Button>
</Grid>
</Grid>
<Grid container item xs={9} className={classes.labelGrid}>
<Typography component="h1" variant="h5">
Something
</Typography>
</Grid>
</Grid>
);
}
EDIT
The gray area on the right hand does not fill the whole screen when the screen size is large, even though the width is set to 100% in the labelGrid
Your buttons have margin (right & left), so they move beyond your left sidebar.
You can fix this using:
classButton: {
margin: theme.spacing(1, 0)
},
submit: {
margin: theme.spacing(1, 0)
},
To add back the space on the left&right side you can add padding on the container:
sideBarGrid: {
maxWidth: 300,
flexDirection: "column",
justifyContent: "space-between",
padding: theme.spacing(0, 1)
},

AppBar overlaps with other elements

I am starting to use React/Material-UI, and also new to CSS etc...
I have a simple page layout with an APPBar. Unfortunately this AppBar overlaps the elements which are meant to go below it.
I have found this answer:
AppBar Material UI questions
But this feels completely wrong. What if my AppBar has a variable height, depending on the icons, display modes etc...?
I have tried to create a vertical grid, to wrap the elements in different items, made the top container a flex one and play with flex settings, nothing seems to work, the app bar always sits on top of the text.
The code is very simple:
import React from 'react';
import { AppBar, Typography, Box } from '#material-ui/core';
function App() {
return (
<div>
<AppBar>
<Typography variant='h3'>
AppBar
</Typography>
</AppBar>
<Box>
<Typography variant='h1' style={{ border: '1px solid black' }}>
Hello
</Typography>
</Box>
</div>
)
}
export default App;
The "Hello" text chunk is only half visible:
This is happening because the MaterialUI App Bar defaults to position="fixed". This separates it from the standard DOM's layout to allow content to scroll beneath it, but as a result no space is made for it on the page.
You can get around this by wrapping all content below it in a div and specifying enough margin, or by changing the position property of <AppBar> so it's no longer "fixed". In your example, you could also just apply the styles to <Box> if that's the only content below the <AppBar>.
e.g.
import React from 'react';
import { AppBar, Typography, Box } from '#material-ui/core';
function App() {
return (
<div>
<AppBar>
<Typography variant='h3'>
AppBar
</Typography>
</AppBar>
<div style={{marginTop: 80}}>
<Box>
<Typography variant='h1' style={{ border: '1px solid black' }}>
Hello
</Typography>
</Box>
</div>
</div>
)
}
export default App;
MaterialUI provides a theme mixin for the AppBar that can help. Not sure if you're using the recomended JSS setup, but you can do something like this:
import withStyles from '#material-ui/core/styles/withStyles';
const styles = theme => ({
appBarSpacer: theme.mixins.toolbar
});
const style = withStyles(styles)
function MyScreen ({ classes }) {
<AppBar></AppBar>
<div className={classes.appBarSpacer}></div>
<Box></Box>
}
export default style(MyScreen)
The mixin will give that div the same height as your AppBar, pushing down the other content.
According to Material-ui, there are 3 solutions to this problem.
https://material-ui.com/components/app-bar/#fixed-placement
You can use position="sticky" instead of fixed. ⚠️ sticky is not supported by IE 11.
You can render a second component
You can use theme.mixins.toolbar CSS
I personally enjoy using the 2nd solution like this.
return (
<>
<AppBar position="fixed">
<Toolbar>{/* content */}</Toolbar>
</AppBar>
<Toolbar />
</>
);
<AppBar position='static'>
use this it will do it and content won't hide under Appear
I think having a good app setup is opinianted, but I would recommend the following
import React from "react";
import ReactDOM from "react-dom";
import {
AppBar,
Typography,
Box,
CssBaseline,
makeStyles,
Container,
Grid,
Toolbar
} from "#material-ui/core";
const useStyles = makeStyles(theme => ({
content: {
flexGrow: 1,
height: "100vh",
overflow: "auto"
},
appBarSpacer: theme.mixins.toolbar,
title: {
flexGrow: 1
},
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
}
}));
function App() {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="absolute">
<Toolbar className={classes.toolbar}>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
className={classes.title}
>
AppBar
</Typography>
</Toolbar>
</AppBar>
<main className={classes.content}>
<div className={classes.appBarSpacer} />
<Container maxWidth="lg" className={classes.container}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box>
<Typography variant="h1" style={{ border: "1px solid black" }}>
Hello
</Typography>
</Box>
</Grid>
</Grid>
</Container>
</main>
</div>
);
}
try this!
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
[theme.breakpoints.down('sm')]: {
marginBottom: 56,
},
[theme.breakpoints.up('sm')]: {
marginBottom: 64,
},
},
menuButton: {
marginRight: theme.spacing(1),
},
title: {
flexGrow: 1,
}, }))
You can add the above to your code like this
const Navbar = () => {
const classes = useStyles()
return (
<div className={classes.root}>
<AppBar position='fixed' color='primary'>
<Toolbar>
<IconButton
edge='start'
className={classes.menuButton}
color='inherit'
aria-label='menu'>
<MenuIcon />
</IconButton>
<Typography variant='h6' className={classes.title}>
News
</Typography>
<Button color='inherit'>Login</Button>
</Toolbar>
</AppBar>
</div>
)}
For more documentation visit material-ui breakpoint customization

Material-UI Typography doesn't center in AppBar

I'm trying center the text in an AppBar. I've tried centering the text in Typography element, using align="center", textAlign="center", and style={{ align: "center" }}, among others:
class App extends React.Component {
render() {
return (
<div>
<AppBar>
<Toolbar>
<Typography
variant="h6"
color="inherit"
style={{ align: "center" }}
>
Header
</Typography>
</Toolbar>
</AppBar>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
... but is doesn't work unless I remove the Toolbar. But then I would have to manually change the height of the AppBar, which I've also not found a way to do. In addition, every instance I've seen of the AppBar uses the Toolbar. All the solutions that I've found that could address this are outdated and don't work (there's no such thing as a ToolbarGroup anymore).
I've also tried using a const styles and exporting the AppBar withStyles():
const styles = {
root: {
flexGrow: 1
},
typography: {
align: "center"
}
};
function Header(props) {
const { classes } = props;
return (
<div className={classes.root}>
<AppBar>
<Toolbar>
<Typography
variant="h6"
color="inherit"
className={classes.typography}
>
Header
</Typography>
</Toolbar>
</AppBar>
</div>
);
}
Header.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(Header);
but it also doesn't work. I'm thinking this should be simple, I'm not sure what I'm missing.
The AppBar component is styled to render its children as flex items.
CSS property like text-align is used for horizontal alignment of children that is displayed different from a flex item e.g. as a table cell, block or inline-block.
Flex items can be centered horizontally using the justify-content or align-self CSS Property or more other ones.
const styles = {
root: {
flexGrow: 1,
},
appbar: {
alignItems: 'center',
}
};
function Header(props) {
const { classes } = props;
return (
<div className={classes.root}>
<AppBar
className={classes.appbar}
color="default"
position="static"
>
<!--...-->
</AppBar>
</div>
);
}
const styles = {
root: {
flexGrow: 1
},
typography: {
flexGrow: 1,
align: "center"
}
};
function Header(props) {
const { classes } = props;
return (
<div className={classes.root}>
<AppBar>
<Toolbar>
<Typography
variant="h6"
color="inherit"
className={classes.typography}
>
Header
</Typography>
</Toolbar>
</AppBar>
</div>
);
}
Header.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(Header);
use flexGrow,
will do the trick and is responsive in mobile also
Adding the following helped me center my title on mobile:
<Box sx={{ flexGrow: 0 }}>
<Box style={{ width: '40px', height: '40px' }}></Box>
</Box>

React Native, How to make a ScrollView load minimum fullscreen without scrollbar but then scroll as content grows

I have a ScrollView that is being problematic because I need to put a bottom border on it, so I need it to load initially as fullscreen, but be able to have the ScrollView automatically increase in height when an <ErrorSection /> component is added.
It doesn't seem to work with just flex: 1, so I am trying to explicitly declare the height and width of the ScrollView, but that is also yielding unpredictable results.
Here's my current code for the ScrollView:
import React from 'react'
import { StyleSheet, ScrollView, Dimensions } from 'react-native'
import * as Animatable from 'react-native-animatable'
const E1ScrollView = ({ children, animation, style, bottomBorder }) => {
const { container, E1bottomBorder } = styles
const { height, width } = Dimensions.get('window')
// const pxHeight = height * PixelRatio.get()
// const pxWidth = width * PixelRatio.get()
return (
<ScrollView style={[container, style]}>
<Animatable.View
style={[{ height, width }, (bottomBorder) ? E1bottomBorder : null]}
animation={animation}
iterationCount={1}>
{children}
</Animatable.View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F0F0F0',
flexDirection: 'column'
},
E1bottomBorder: {
borderBottomWidth: 5,
borderColor: '#DD0426',
}
})
export { E1ScrollView }
I have solved this after much research. Here is my scrolling view component fully functional:
import React from 'react'
import { StyleSheet, ScrollView } from 'react-native'
import * as Animatable from 'react-native-animatable'
const E1ScrollView = ({ children, animation, bottomBorder, style }) => {
const { container, E1bottomBorder } = styles
// the key is flexGrow: 1 on the ScrollView (and contentContainerStyle)
// The wrapped <View /> should be flex: 1
return (
<ScrollView
contentContainerStyle={{ flexGrow: 1 }}
scrollEnabled>
<Animatable.View
style={[container, (bottomBorder) ? E1bottomBorder : null, style]}
animation={animation}
iterationCount={1}>
{children}
</Animatable.View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F0F0F0',
flexDirection: 'column'
},
E1bottomBorder: {
borderBottomWidth: 5,
borderColor: '#DD0426',
}
})
export { E1ScrollView }
If you would like to sample it, simply import that "common" component in to whatever screen you plan to use it and do this:
import { E1ScrollView } from '../common'
// ...
// Notice how you can overwrite styles by adding style={{ backgroundColor: 'red' }} to <E1ScrollView />
return (
<E1ScrollView animation="fadeIn" bottomBorder>
<View style={{ flex: 0 }}><Text>test</Text></View>
<View style={{ flex: 0, flexDirection: 'column' }}>
<Text>test</Text>
<Text>test</Text>
<Text>test</Text>
</View>
<View style={{ flex: 1 }} />
<View style={{ flex: 0 }}><Text>test</Text></View>
</E1ScrollView>
)
The part I would like to make sure you're aware of is you can create <CardSection /> View elements that have either flex: 0 or flex: 1 style and you will get effortless stacking. Then, you just need to work with margins and padding.
The <View style={{ flex: 1 }} /> element as I demonstrated above is a critical design element to be aware of, in my opinion. I found it somewhere along my journeys and it makes filling areas pretty effortless.
If your screen receives props that add DOM elements, your view will respond in an expected manner.

Resources