Styling Grid to have more elements than text - css

I have grid from material UI:
Item element
const Item = styled(Paper)(({theme}) => ({
...theme.typography.body2,
padding: theme.spacing(2),
textAlign: 'center',
color: "black",
}));
Structure
<div className="wrapper">
<Typography variant="h3" component="h3">
List of friends
</Typography>
<div className="friends">
<Grid container
direction="row"
rowSpacing={1}
spacing={{xs: 2, md: 3}} columns={{xs: 4, sm: 8, md: 12}}
alignItems="center"
justifyContent="center"
>
{
friends.map((friend, i) => {
return <Grid item xs={4} sm={6} md={6} mt={5}>
<Item className="item"><span>{i}</span>{friend.name}</Item>
</Grid>
})
}
</Grid>
</div>
</div>
With css:
.wrapper{
width: 100%;
position: relative;
align-items: center;
display: flex;
flex-direction: column;
background:#eaeaea
}
.friends{
position: relative;
width: 75%;
}
It looks like this:
However, i would like the number of friend, to be on the left, and highlighted like:
However, how to stile the <span> element to do this? The when i style span to be
span{
position: absolute;
left: 0
width:25%;
height: 100%
}
Then the span is somewhere else, as the material ui uses lot of styling that makes this hell.
when i change it to:
{
countries.map((friend, i) => {
return <Grid item xs={4} sm={6} md={6} mt={5} >
<span> i </span>
<Item className="item">{friend.name}</Item>
</Grid>
})
}
I would need to make adjustments to the Grid elements, adding position relative and such, but im not sure how this would work with responsivity.
Is there simple way to do this?
Or is there any other component i can use instead of Item(Paper) element?
Thanks for help!

You can use display: grid on the Paper element, like so:
<Paper
sx={{
display: 'grid',
grid: 'auto / 25% 75%',
height: 50,
'& > div': {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100%',
},
}}
>
<Box>1</Box>
<Box>Name</Box>
</Paper>
Alternatively, you can do it with flex: 1 and flex: 3, but I think the grid method is easier to set up, since all the logic is in one line.

Related

Make Material UI Grid container grow with flexGrow

I am creating a chat window where I have my users on the left and my messages on the right.
The thing is I want both columns to grow to the end of the viewport or till the footer but there is no way to make it works. Here is my component.
import Grid from "#material-ui/core/Grid";
const Prueba = () => {
return (
<div style={{ display: "flex" }}>
<Grid container spacing={1} style={{ flexGrow: 2 }}>
<Grid
item
xs={12}
sm={12}
md={4}
lg={3}
style={{ background: "black" }}
></Grid>
<Grid
item
xs={12}
sm={12}
md={8}
lg={9}
style={{ background: "blue" }}
></Grid>
</Grid>
<div
style={{
position: "fixed",
bottom: 0,
height: 100,
width: "100%",
backgroundColor: "red",
}}
></div>
</div>
);
};
export default Prueba;
The container is inside a flex element and the Grid Container has flexGrow property 1. What is not working here?
Here is how it renders now. It's like my Grid container has no height and actually I want it to grow all down to the footer.
You can do this in material-ui with css grid
https://codesandbox.io/s/naughty-yonath-wqr1p?file=/src/App.js
import { styled } from "#material-ui/core";
const Grid = styled("div")({
display: "grid",
gridTemplateColumns: "1fr 3fr",
height: "100vh"
});
const Footer = styled("div")({
position: "fixed",
bottom: 0,
height: 100,
width: "100%",
backgroundColor: "tomato"
});
export default function App() {
return (
<div className="App">
<Grid>
<div style={{ background: "khaki" }}>Left</div>
<div style={{ background: "lightsalmon" }}>Right</div>
</Grid>
<Footer />
</div>
);
}

MaterialUI Box takes over background image

I have a react component that contains a forms and it is formatted as follows:
<Box
display="flex"
justifyContent="center"
alignItems="center"
style={{ minHeight: "100vh", backgroundColor: "gray", opacity: "0.8" }}
> ...
</Box>
This componenent, called Form is then passed in App.js as follows:
import React from "react";
import Form from "./components/Form";
const sectionStyle = {
height: "100vh",
backgroundImage:
"url('www.blablabla.com/img.jpg') ",
backgroundRepeat: "no-repeat",
backgroundSize: "cover"
};
const App = () => {
return (
<div style={sectionStyle}>
<Form />
</div>
);
};
export default App;
However, the results I get is this one:
I added the opacity to better show that my Box component is 'stretched' all over the window, while I would like it to just wrap its content, so that if some opacity is applied, it will only appear I side the Box, and the background image will be normal.
How can I achieve this?
material-ui Box's default component is a div. see material-ui Box
A div's default behavior is to stretch horizontally across the available space. That is why your Box is stretching horizontally. Where is the default size of a div element defined or calculated?
The minHeight: "100vh" style you are applying to the Box is telling it to stretch across the available vertical space. That is why your Box is stretching vertically.
see Fun with Viewport Units
Perhaps using the Grid component as a wrapper will give you what you are looking for
<Grid container className={props.classes.sectionStyle}
direction="column"
justify="space-evenly"
alignItems="center"
>
<Grid item>
<Form />
</Grid>
</Grid>
This would change your code to be:
import React from "react";
import {Grid} from '#material-ui/core';
import Form from "./components/Form";
const sectionStyle = {
height: "100vh",
backgroundImage:
"url('www.blablabla.com/img.jpg') ",
backgroundRepeat: "no-repeat",
backgroundSize: "cover"
};
const App = () => {
return (
<Grid style={sectionStyle}
container
direction="column"
justify="space-evenly"
alignItems="center"
>
<Grid item>
<Form />
</Grid>
</Grid>
);
};
export default App;
I would suggest you to use pseudo elem like:after and :before
Here is an example.
.background-filter::after {
content: "";
display: block;
position: absolute;
width: 100%;
height: 100%;
opacity: .8;
background: red;
}
.background-filter {
position: relative;
}
.background {
background-image: url('https://upload.wikimedia.org/wikipedia/en/6/62/Kermit_the_Frog.jpg');
width: 200px;
height: 200px;
}
.background span{
position: absolute;
z-index: 1;
}
<div class="background background-filter"><span>Hello World I am text with background blur</span></div>
Do what ever you want to apply to ::after wont effect the form above

How do align content to the center in flexbox

I have a item that i want to be align to the middle and one to the bottom.
I want the logo image in the center, but I can't figure out how to do it.
import React, { Component } from 'react';
import { Container, Content, Text, Button, View } from 'native-base';
import { StyleSheet, Image } from 'react-native'
export default class WelcomeScreen extends Component {
render() {
return (
<Container>
<Content contentContainerStyle={styles.container}>
<View style={styles.imgContainer}>
<Image
source={require('../../assets/images/logos/logo.png')}
/>
</View>
<View style={styles.btnContainer}>
<Button block primary onPress={() => this.props.navigation.navigate('Signin')} rounded>
<Text>Sign in</Text>
</Button>
<Button block light style={{ marginTop: 15 }} onPress={() => this.props.navigation.navigate('Signup')} rounded>
<Text>Sign up</Text>
</Button>
</View>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
imgContainer: {
flex: 1,
},
btnContainer: {
width: 300,
}
})
Try this
imgContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
Here's an HTML CSS only example for you that you can easily tweak to solve your problem.
body {
margin: 0;
}
#main {
display: flex;
flex-direction: column;
height: 100vh;
justify-content: space-between;
}
.container {
align-items: middle;
margin: 0 auto;
align-self: middle;
width: 300px;
height: 80px;
background-color: steelblue;
vertical-align: afar;
}
<div id="main">
<div class="container">
abc
</div>
<div class="container">
xyz
</div>
</div>
The trick lies in the following CSS properties:
flex-direction: column
justify-content: space-between
if you want the image to align center in the screen except for the button height, you can use the following code, and replace the view in ImageContainer to Image
render() {
return (
<Container>
<View
style={styles.imgContainer}>
<View style={{backgroundColor:'red',height:50,width:50}} />
</View>
<Content contentContainerStyle={styles.container}>
<View style={styles.btnContainer}>
<Button block primary onPress={() => this.props.navigation.navigate('Signin')} rounded>
<Text>Sign in</Text>
</Button>
<Button block light style={{ marginTop: 15 }} onPress={() => this.props.navigation.navigate('Signup')} rounded>
<Text>Sign up</Text>
</Button>
</View>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'flex-end'
},
imgContainer: {
position:'absolute',
justifyContent:'center',
alignItems:'center',
height:Dimensions.get('window').height-40,
width:Dimensions.get('window').width,
flex: 1,
},
btnContainer: {
height:200,
width: 300,
alignItems:'center',
justifyContent: 'flex-end',
marginBottom:20
}
})

Make Item go the bottom using Flexbox and Material UI

I am trying to add Unassigned Text to the bottom of my Container, as shown in this mockup:
Below is the code, that I have so far. I am struggling to get the border between the play button working too. I have tried the usual css: bottom:0 and position:relevant Along with Flexbox but it doesn't seem to want to go to the very bottom of the container.
const styles = theme => ({
root: {
flexGrow: 1,
overflow: 'hidden',
padding: theme.spacing(0, 3),
},
paper: {
maxWidth: 800,
margin: `${theme.spacing(2)}px auto`,
padding: theme.spacing(2),
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: 200,
},
playButton: {
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
position: "relative",
"& .playButton": {
position: "absolute",
top: "60%",
left: "-55px",
transform: "translateY(-50%)",
},
"& .star-rating": {
"& .fa-star": {
"&:hover": {
"&::before": {
content: "\f005",
color: "yellow"
}
}
}
},
},
});
function Tasks(props) {
const { classes } = props;
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<Grid container spacing={2}>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div className="name-label">
Name
</div>
<Typography variant="h6" gutterBottom>
{props.name}
</Typography>
<div className="form-divider"></div>
<Typography variant="body2" color="textSecondary">
{props.description}
</Typography>
</Grid>
</Grid>
<Grid item classes={{ root: props.classes.playButton}}>
<Grid item xs={3} className="playButton">
<i class="far fa-play-circle fa-2x"></i>
</Grid>
<div className="workers-assigned-label">
Workers Assigned
</div>
<Typography variant="h6" gutterBottom>
0/25
</Typography>
<div class="star-rating">
<label class="far fa-star fa-2x"></label>
<label class="far fa-star fa-2x"></label>
<label class="far fa-star fa-2x"></label>
</div>
<div className="dropdown-menu">
<h5>Unnassigned</h5>
</div>
</Grid>
</Grid>
</Grid>
</Paper>
</div>
);
}
export default withStyles(styles)(Tasks);
Any input would be great.
I would recommend starting with a Grid 'skeleton' that looks something like:
<Grid container>
<Grid item container xs={8} direction="column" justify="flex-start">
// Left column contents, with each row as a <Grid item>
</Grid>
<Fab className={classes.fab}><PlayIcon /><Fab>
<Grid item container xs={4} direction="column" justify="space-between" className={classes.right}>
// Right column contents, with each row as a <Grid item>
</Grid>
</Grid>
The direction=column will help you position items vertically within each container. The justify=space-between will ensure that your first item is at the top of the container and your last item (the unassigned text) is at the bottom.
The "right" css class looks like:
right: {
borderLeft: `1px solid ${theme.palette.grey[500]}`,
position: "relative"
}
You can give it a position of "relative" to make it easier to position the fab relative to the column. The "fab" class looks like:
fab: {
position: "absolute",
margin: "auto",
top: 0,
bottom: 0,
left: -28
}
The margin, top, and bottom properties help center the fab vertically, and the left is a bit of a hack based on the dimensions of the fab to center it over the border.
Here's a working draft that brings everything together: https://codesandbox.io/s/tender-torvalds-dlbke?fontsize=14
You can try something like this, or give flex: 1 to anything in the column to make it stretch.
const styles = theme => ({
playButton: {
'& .dropdown-menu': {
marginTop: "auto"
}
}
})

How do I create this layout in Flexbox?

I'm trying to create this layout in Flexbox (and React Native) but I can't get it to work. Specifically, the Left and Right buttons refuse to expand to 50% of the width of the container no matter what I do. They are always the size of their content.
I'm using nested containers. The buttons are in a columnar Flex container which is nested in a row Flex container that also contains the image.
Here is my JSX:
<View style={{
display: 'flex',
flex: 1,
flexDirection: 'column'}}>
<Image
style={{flex: 1, zIndex: 1, width: '100%', height: '100%'}}
resizeMode='cover'
resizeMethod='resize'
source={require('./thumbs/barry.jpg')}
/>
<View style={{
display: 'flex',
flexDirection: 'row',
flex: 0,
width: '100%',
height: 100}} >
<Button style='flex: 1' title="LEFT" onPress={() => {}} />
<Button style='flex: 1' title="RIGHT" onPress={() => {}} />
</View>
</View>
All replies are much appreciated...
Maybe this will help you:
.container{
display: flex;
flex-wrap: wrap;
width: 500px;
}
.image{
height: 500px;
flex-basis: 100%;
background-color: green;
}
.button{
box-sizing: border-box;
flex-basis: 50%;
height: 100px;
background-color: red;
border: solid 1px black;
}
<div class="container">
<div class="image"></div>
<div class="button"></div>
<div class="button"></div>
</div>
If you ever have issues with using flexbox, use this resource, it's really helpful for solving flexbox issues. Hopefully you can solve your problem now.
You dont want to use height properties, but using it is a good way to achieve what you want. Here is an example:
You set the image to 90% of the screen height and the buttons container to 10%.
Each button has 50% width
HTML
<div class="container">
<div class="image"></div>
<div class="buttons-container">
<button>Action 1</button><button>Action 2</button>
</div>
</div>
CSS
* {
box-sizing: border-box;
}
body, html {
height: 100%;
margin: 0;
}
.container {
position: relative;
width: 100%;
height: 100%;
}
.container .image {
width: 100%;
height: 90%;
background-image: url('path/to/image');
position: relative;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.container .buttons-container {
display: flex;
height: 10%;
}
.container .buttons-container button {
width: 50%;
}
Check the example working - https://codepen.io/kaiten/pen/YaYqZO
In consideration of the fact that your code is required in react-native and not react, try this piece of code
<View style={flex:1}>
<Image source={require(path)} style={flex:1}>
<View style={flex:1}>
<View style={flex:1}>
<Button style={flex:1,height:100} title='Left'/>
</View>
<View style={flex:1}>
<Button style={flex:1,height:100} title='Right'/>
</View>
</View>
</View>
Explanation : In react-native you do not need to mention display:flex in your styles since react-native always uses flexBox. When you do flex:1 your container always takes the 100% of the width and the height of it's parents hence doing flex:1,height:'100%',width:'100%' is invalid.
In your
<View style={{
display: 'flex',
flexDirection: 'row',
flex: 0,
width: '100%',
height: 100}} >
you've done flex:0 so this is the equivalent of width:'0%',height:'0%'
Hope this gives you some clarity on the code required.
PS: There might be a possibility that the code i wrote might not work properly due to the <Image> width and height. For eg : If the height of the image decreases and you've given fixed height to your buttons then there might be some white space below your buttons since the height of the <Image> plus the height of the <Button> will not add up to the height of the screen visible.
It seems like Button component do not take style as prop if we look at the codebase of React Native. So the problem is button is not accepting style. So I wrapped button with a view.
Here is sample of working code:
<View style={{
flex: 1,
}}>
<Image
style={{ flex:1, zIndex: 1, width: '100%', height: '100%'}}
resizeMode='cover'
resizeMethod='resize'
source={require('./thumbs/barry.jpg')}
/>
<View style={{
flexDirection: 'row',
height: 100}} >
<View style={{flex:1}}>
<Button title="LEFT" onPress={() => {}} />
</View>
<View style={{flex:1}}>
<Button title="RIGHT" onPress={() => {}} />
</View>
</View>
</View>

Resources