Related
I am trying to wrap a page in a React project in a material UI container but it squeezes in all my content with these weird margins. Here is what it looks like:
But I want it to look like this with full width:
Haven't been able to find any other resources explaining how to change the width of the container. Does anyone have any workarounds? I tried adjusting the width of the container to be 100vw but it was unresponsive to my CSS. Here is my code:
////BUY PAGE
import React from 'react';
import Container from '#mui/material/Container';
import AppBar from '../../components/AppBar/AppBar';
import Footer from '../../components/Footer/Footer';
import './Buy.css';
const Buy = () => {
return (
<Container>
<AppBar />
<Footer />
</Container>
);
};
export default Buy;
////CSS
.buy-container {
overflow-y: hidden;
width: 100vw;
}
You should be able to get the results you're looking for by setting the maxWidth property of Container to false e.g:
<Container maxWidth={false}>
<AppBar />
<Footer />
</Container>
Edit:
The maxWidth property determines the max-width of the container. The container width grows with the size of the screen. By setting it to false you can disable the maxWidth property.
https://mui.com/api/container/
You will need to add maxWidth={false} and disableGutters properties to the <Container/> component. Additionally, you should include the <CssBaseline/> component to reset the browser's CSS.
Example:
<>
<CssBaseline />
<Container maxWidth={false} disableGutters>
{children}
</Container>
</>
Container API
Name
Type
Default
Description
maxWidth
'xs', 'sm', 'md', 'lg', 'xl', false, string
Determine the max-width of the container. The container width grows with the size of the screen. Set to false to disable maxWidth.
disableGutters
bool
false
If true, the left and right padding is removed.
You should avoid to set the custom container width until changing the breakpoints.
Otherwise, you can use a custom div element or Box component.
// makeStyles
const useStyles = makeStyles(() => ({
root: {
height: '100%',
overflow: 'hidden',
width: '100%'
},
}));
// styled
const LayoutContainer = styled('div')(() => ({
height: '100%',
overflow: 'hidden',
width: '100%'
}));
I'd take a look at global css variables to overwrite the standard (see here):
The material docs suggest this way or using styling overrides which may be another option for you.
.MuiContainer-root {
width: 100vw;
padding-left: 0;
padding-right: 0;
}
FYI - I got the global css name from the Container portion of the docs under "root", in case you've not seen it.
I would use the <Container> within <Box>/<Appbar> that has the background color e.g:
<Box sx={{ bgcolor: 'black'}}>
<Container>
My content
</Container>
</Box>
minHeight: '100%' worked for me in that kind of situation
I have my App.js class which renders as
const theme = createMuiTheme({
palette: {
primary: lime,
secondary: {
...grey,
A400: '#00e677'
},
error: red
}
});
class App extends Component {
render() {
const classes = this.props.classes;
return (
<div className={classes.root}>
<MuiThemeProvider theme={theme}>
<MyApp/>
</MuiThemeProvider>
</div>
);
}
}
export default withStyles(styles)(App);
my root class has this style
const styles = theme => ({
root: {
width: '100%',
height: '100%',
marginTop: 0,
zIndex: 1,
overflow: 'hidden',
backgroundColor: theme.palette.background.default,
}
});
I thought that by setting height:'100%' I'd had all my window filled, the problem is that I've got a blank space (wrt the grey background) below the MyApp's div, see attached image.
How can I force the background color to fill 100% of the window?
Instead of using height:100% you may try height:100vh. Using % is relative to the parent height but using vh is relative to the height of the viewport. So making 100vh will ensure that the block fill all the height of the screen.
You can read more about here
This is a version of Temani Afif's answer.
I use Grommet within React.
To fill the whole screen with my theme background (dark!) I styled the style provider HOC thus:
import styled from 'styled-components';
FillGrommet = styled( Grommet )`min-height: 100vh;`;
then, in render() I wrote:
return (
<this.FillGrommet theme={ dark }>
<AppBar /
...
It is recommended to apply the style outside render() for performance reasons.
html {
background-color: *color of your choice*,
}
This changes the whole background past 100vh and 100vw.
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.
I want to do width: 100% - 50 so I can add an icon which is 50 wide on the right hand side of it.
I have got width: 100% - 20% working by using react-native-extended-styles but I don't see why that is useful because you can do width: '80%'. I cannot get width: 100% - 50 working. Is there a way?
Trying to use the onLayout event to get the container width, then set the <autocomplete> to 100% - 50 of the container width but it isn't working.
let Location = (props) => {
let locationInputElement
const blur = () => {
locationInputElement.blur()
}
let inputContainerWidth
return (
<View style={styles.formItem}>
<View
onLayout={(event) => {
inputContainerWidth = event.nativeEvent.layout.width
console.log(inputContainerWidth)
}}
<Autocomplete
data={props.autocompleteResults.predictions}...
style={{
borderRadius: 8,
backgroundColor: 'red',
alignSelf: 'stretch',
paddingLeft: 10,
position: 'relative',
...styles.label,
...styles.labelHeight,
width: inputContainerWidth - 50
}}
/>
</View>
</View>
)
}
It does console.log 335 when it console.logs inputContainerWidth but the width of the <autocomplete> is 100% still.
I'd agree with Viktor, you should be able to achieve this using Flex Box.
Here's something I put together: https://snack.expo.io/B1jDKOhyb
You set the flexDirection of the formRow to row, and then the first child (the holder View for your AutoComplete component to flex: 1. This makes it fill all available space. The next child View is your icon holder. Which you can set to whatever value you want (in this case 50).
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.formRow}>
<View style={styles.formItem}>
// AutoComplete component goes here
</View>
<View style={styles.formIcon}>
// Icon goes here
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100
},
formRow: {
flexDirection: 'row',
height: 50,
},
formItem: {
flex: 1,
backgroundColor: 'dodgerblue',
},
formIcon: {
width: 50,
backgroundColor: 'greenyellow',
},
});
This can easily be solved by using Dimensions.
import { Dimensions } from 'react-native';
const MyComponent = () => {
return <Text style={{height: Dimensions.get('window').height - 100}}></Text>
};
export default MyComponent;
You can do it without computing width. Use marginHorizontal: 50 with width:100 or flex:1.
Your code not working because, it's rendered then inputContainerWidth updated. To make it work, there should be another render with new inputContainerWidth. So you can't use a stateless component. Change Location to regular component and add inputContainerWidth to state.
Consider using useWindowDimensions from react-native (see docs):
import { useWindowDimensions } from 'react-native';
const { height, width } = useWindowDimensions();
I did margin: -50 in the parent and it worked for me
Suppose this is the layout:
<View style={styles.container}>
<View style={styles.titleWrapper}>
...
...
</View>
<View style={styles.inputWrapper}>
...
...
</View>
<View style={styles.footer}>
<TouchableOpacity>
<View style={styles.nextBtn}>
<Text style={styles.nextBtnText}>Next</Text>
</View>
</TouchableOpacity>
</View>
</View>
I want to make the view with the styles of footer to position at the bottom of the screen. I tried giving the alignSelf property to the footer, but instead of positioning at the bottom, it positions it to the right side of the screen. How can I make the footer item stick to the end? Thank you.
I would use the following approach:
<View style={styles.container}>
<View style={styles.contentContainer}> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</View>
<View style={styles.footer}>
...
</View>
</View>
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
titleWrapper: {
},
inputWrapper: {
},
contentContainer: {
flex: 1 // pushes the footer to the end of the screen
},
footer: {
height: 100
}
});
This way the styles of titleWrapper and inputWrapper can be updated without breaking the layout of your app and the components themselves are easier to re-use :)
In React Native, the default value of flexDirection is column (unlike in CSS, where it is row).
Hence, in flexDirection: 'column' the cross-axis is horizontal and alignSelf works left/right.
To pin your footer to the bottom, apply justifyContent: 'space-between' to the container
for me the answer was to create a container view for the elements, then for the style.
bottomContainer: {
flex: 1,
justifyContent: 'flex-end',
}
Absolutely position is another way to fix footer, just like:
footer: {
position: 'absolute',
height: 40,
left: 0,
top: WINDOW_HEIGHT - 40,
width: WINDOW_WIDTH,
}
To fix a View to the bottom, simply use: marginTop: 'auto' .
This worked for me after searching like an hour on the net. I tried experimenting and it worked!
Consider a screen structure
<View style={styles.container}>
<View style={styles.body}> ... </View>
<View style={styles.footer}>...</View>
</View>
You can do it cleanly using Flexbox approach utilizing flex-grow.
const Styles = StyleSheet.create({
container:{
flexDirection: 'column', // inner items will be added vertically
flexGrow: 1, // all the available vertical space will be occupied by it
justifyContent: 'space-between' // will create the gutter between body and footer
},
})
Note: In case of nested elements, you have to ensure that the parent container has enough height to work with when using flexGrow. Set backgroundColor on parents and child to debug.
To do this you can use the Stylesheet element position: 'absolute'.
/*This is an Example to Align a View at the Bottom of Screen in React Native */
import React, { Component } from 'react';
import { StyleSheet, View, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.containerMain}>
<Text> Main Content Here</Text>
<View style={styles.bottomView}>
<Text style={styles.textStyle}>Bottom View</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
containerMain: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
bottomView: {
width: '100%',
height: 50,
backgroundColor: '#EE5407',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0, //Here is the trick
},
textStyle: {
color: '#fff',
fontSize: 18,
},
});
You can use this style:
row: {
flexDirection: 'row',
height: 50,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0,
}
embed other content in a scrollview
<View style={styles.container}>
<ScrollView> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</ScrollView>
<View style={styles.footer}>
...
</View>
</View>
In react native, there are some properties like position: 'absolute', bottom: 0, which you will want to give to your button view
Quick example in essence, based on #David's answer:
<View style={{flex: 1}}>
<View style={{flex: 1}}>
<Text>Main content</Text>
</View>
<Text>Footer</Text>
</View>
import React from 'react'
import { View, StyleSheet } from 'react-native'
function moveToBottom(component) {
return (
<View style={styles.container}>
{component}
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-end',
marginBottom: 36
}
})
export default moveToBottom
Now in our screen, we just need to import:
import moveToBottom from 'library/utils/moveToBottom'
and wrap our button:
{
moveToBottom(
<ImageButton
style={styles.button}
title={strings.onboarding.welcome.button}
onPress={() => {
this.props.navigation.navigate('Term')
}} />
)
}
I tested it and I approve it's the best option to respect the layout without having fixed things to bottom, which is not possible if you use react-native-web in addition of react-native, because people resize and elements overlap on each over.
Source: https://medium.com/react-native-training/position-element-at-the-bottom-of-the-screen-using-flexbox-in-react-native-a00b3790ca42
I have a case in which I have to show a image in the bottom like this, as you can see the sky-blue image is not poped-up with keyboard.
so for this I have created a functional component for image in bottom.
import React, { useEffect, useState } from "react";
import { Keyboard, View, Image } from "react-native";
export const BottomImage = (props) => {
const [shouldShow, showImage] = useState(true);
useEffect(() => {
Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
return () => {
Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
};
}, []);
let _keyboardDidShow = () => {
showImage(false)
}
let _keyboardDidHide = () => {
showImage(true)
}
return (<ViewToRender show={shouldShow} src={props.image} />)
}
function ViewToRender(props) {
return props.show ? <Image style={{ position: 'absolute', bottom: 0 }} source={props.src} /> : <View />
}
and to use this Bottom image you have to pass your image to it like :
<BottomImage image={AppImage.signupbottom} />
This can be a bit tricky given that parent components can still affect the height of children with 'absolute' styles, I also tried doing "bottom: 0, height: 'auto'" like with normal HTML/CSS, but it didn't work out well, down the line I'll probably create a general component which makes sure the view can fit into the screen size. End result of view with contents
<View> component parameters
style={{
position: 'absolute',
left: 0,
padding: ContainerPadding,
top: TopOffset,
width: ScreenWidth
}}
onLayout={(event) => {
var {x, y, width, height} = event.nativeEvent.layout; // get the View's dimensions after 1st render
SetTopOffset(ScreenHeight - height - HeaderHeight); // Set 'top' to: screen size - height (of view) - parent top offset (optional if no parent offset)
}}
With useState:
const [TopOffset, SetTopOffset] = useState<number>(0); // Controls 'top' of screen
HeaderHeight is the height which is added to all my page components, you can remove this variable if you do not have any top spacing. (currently set to 64 default and this variable is updated based on device)
ScreenWidth & ScreenHeight are calculated here: export const ScreenWidth = Dimensions.get('screen').width; export const ScreenHeight = Dimensions.get('screen').height;
ContainerPadding is a general padding number used across my project (currently set to 12.5)