I'm using Mantine.dev with Nextjs and I have this part design.
I have a list of strings, the length is unknown, there might be any amount and in a wide viewport they can wrap as many there are, no max height limit but in a small viewport, there should be only 2 rows in a way that it makes horizontal scrolling
This is what it currently looks like in small viewport
The code
<ScrollArea>
<Flex wrap='wrap' rowGap={10} columnGap={8} h={{ base: 65, sm: 'auto' }}>
{services.map((service, i) => (<Button>{service}</Button>))}
</Flex>
</ScrollArea>
You can achieve this with a MediaQuery component and a Box component instead of Flex because we need to change our layout from display: flex; to column-count: 2; and change writing-mode: vertical-lr; to get the result.
import { ScrollArea, Button, Box, MediaQuery } from "#mantine/core";
const services = [
"Frontend",
"Backend",
"FullStack",
"DevOps",
...
];
export default function App() {
const boxStyles = {
display: "flex",
justifyContent: "flex-start",
flexWrap: "wrap",
columnGap: 8,
rowGap: 10
};
const boxStylesSM = {
display: "block",
columnCount: 2,
columnGap: 10,
writingMode: "vertical-lr"
};
const buttonStyle = {
display: "flex",
justifyContent: "center",
alignItems: "center",
whiteSpace: "nowrap"
writingMode: "horizontal-tb" // Fix for Firefox
};
const buttonStyleSM = {
marginRight: 8
};
return (
<div className="App">
<ScrollArea type="auto" sx={{ padding: "0.8rem 0.5rem" }}>
<MediaQuery smallerThan="sm" styles={boxStylesSM}>
<Box sx={boxStyles}>
{services.map((service, i) => (
<MediaQuery smallerThan="sm" styles={buttonStyleSM}>
<Button sx={buttonStyle} key={i}>
{service}
</Button>
</MediaQuery>
))}
</Box>
</MediaQuery>
</ScrollArea>
</div>
);
}
Related
How do you align items to the left and the right in React Native?
Whatever combination of flexbox properties I try, the two sets of text are stuck next to each other like this:
How do you make it so "Sign In" is on the right side of the screen and Repositories on the left?
Here is my code:
import { View, StyleSheet, Text, ScrollView } from 'react-native';
import Constants from 'expo-constants';
import { Link } from "react-router-native";
const styles = StyleSheet.create({
container: {
paddingTop: Constants.statusBarHeight,
paddingLeft: 10,
paddingBottom: 20,
backgroundColor: 'grey',
},
text: {
fontSize: 20,
color: 'white',
fontWeight: 'bold'
},
linkText: {
color: 'white',
},
nesteddivleft: {
flex: 1,
display: "flex",
justifyContent: "flex-start",
alignItems: "center",
},
nesteddivright: {
flex: 1,
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
},
scrollbar: {
display: 'flex',
justifyContent: 'space-between'
}
});
const AppBar = () => {
return <><View style={styles.container}>
<ScrollView style="scrollview" horizontal>
<View style={styles.nesteddivleft}><Link to="/"><Text style={styles.text}>Repositories</Text></Link></View>
<View style={styles.nesteddivright}><Link to="/signin"><Text style={styles.linkText}>Sign In</Text></Link></View>
</ScrollView>
</View>
</>
};
export default AppBar;
App:
import Main from './src/components/Main'
import { StatusBar } from 'expo-status-bar';
import { NativeRouter } from 'react-router-native';
export default function App() {
return (
<>
<NativeRouter>
<Main/>
</NativeRouter>
<StatusBar style="auto" />
</>
);
}
As you can see, I have tried putting justify-content: space-between on the parent div and that does nothing.
I also tried this solution and it has done nothing: Aligning elements left, center and right in flexbox
import { View, StyleSheet, Text, ScrollView } from 'react-native';
import Constants from 'expo-constants';
import { Link } from "react-router-native";
const styles = StyleSheet.create({
container: {
paddingTop: Constants.statusBarHeight,
paddingLeft: 10,
paddingBottom: 20,
backgroundColor: 'grey',
display: "flex",
justifyContent: "space-between",
minWidth: '100%',
flexDirection: "row"
},
text: {
fontSize: 20,
color: 'white',
fontWeight: 'bold'
},
linkText: {
color: 'white',
},
nesteddivleft: {
},
nesteddivright: {
},
scrollbar: {
}
});
const AppBar = () => {
return <><View style={styles.container}>
<View style={styles.nesteddivleft}><Link to="/"><Text style={styles.text}>Repositories</Text></Link></View>
<View style={styles.nesteddivright}><Link to="/signin"><Text style={styles.linkText}>Sign In</Text></Link></View>
</View>
</>
};
export default AppBar;
Steps to solve issue:
Take out the scrollview component.
set Display to flex, justify Content to space-between, minWidth to 100% AND flex Direction to Row in parent component.
Not optimal as I need the Scrollview component in there as well, I will need to find a solution that allows me to have that component as a child.
I would like a scroll to the top button to sit at the bottom, much like a footer. Current Behavior: I have an array I'm filtering through and displaying different lengths of data. When there is only one item in a certain category the button will move all the way to the top of the page under the item. Wanted Behavior: I would like the button to stay at the bottom and not move, but not sticky. my button styling is as follows:
import React, { useState, useContext } from "react"
// components
import SelectStatus from "../components/SelectStatus"
import RepoCard from "../components/RepoCard"
// Context
import { GithubContext } from "../context/GithubContext"
// Material UI Stuff
import TextField from "#material-ui/core/TextField"
import CardContent from "#material-ui/core/CardContent"
import Button from "#material-ui/core/Button"
import Card from "#material-ui/core/Card"
import Grid from "#material-ui/core/Grid"
import { makeStyles } from "#material-ui/core/styles"
import Container from "#material-ui/core/Container"
// context
const useStyles = makeStyles((theme) => ({
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8),
},
card: {
display: "flex",
marginBottom: 10,
minHeight: 90,
},
form: {
display: "flex",
alignItems: "center",
width: "100%",
},
content: {
display: "flex",
alignItems: "center",
width: "100%",
justifyContent: "space-between",
},
jobField: {
margin: 0,
padding: 0,
},
grid: {
padding: 0,
},
dashboardContainer: {
marginTop: 70,
padding: 10,
},
loading: {
textAlign: "center",
},
}))
const INITIAL_STATE = {
language: "All",
search: "",
}
const Profile = () => {
const [formData, setFormData] = useState(INITIAL_STATE)
const [updated, setUpdated] = useState(false)
const [created, setCreated] = useState(false)
const { data } = useContext(GithubContext)
const handleUpdated = () => {
setUpdated(!updated)
data &&
data.sort((a, b) => {
if (updated) return a.updated_at > b.updated_at ? -1 : 1
return a.updated_at > b.updated_at ? 1 : -1
})
}
const handleCreated = () => {
setCreated(!created)
data &&
data.sort((a, b) => {
if (created) return a.created_at > b.created_at ? -1 : 1
return a.created_at > b.created_at ? 1 : -1
})
}
const handleInputChange = (field) => (e) => {
setFormData({ ...formData, [field]: e.target.value })
}
const classes = useStyles()
return (
<>
<div style={{ marginTop: 85, marginBottom: 85 }}>
<Container className={classes.dashboardContainer}>
<Card className={classes.card} style={{ width: "100%" }}>
<CardContent className={classes.content}>
<div className={classes.form}>
<Grid
container
spacing={2}
alignItems='center'
justify='space-between'
>
<Grid item sm={4} xs={12} className={classes.grid}>
<SelectStatus
language={formData.language}
handleInputChange={handleInputChange}
/>
</Grid>
<Grid item sm={4} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin='normal'
fullWidth
id='search'
name='search'
label='Search by Title'
placeholder='Search by Title'
onChange={handleInputChange("search")}
value={formData.search}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<Button
fullWidth
variant='contained'
color='primary'
onClick={handleUpdated}
>
Updated {updated ? "(oldest)" : "(newest)"}
</Button>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<Button
fullWidth
variant='contained'
color='primary'
onClick={handleCreated}
>
Created {created ? "(oldest)" : "(newest)"}
</Button>
</Grid>
</Grid>
</div>
</CardContent>
</Card>
</Container>
{!data ? (
<h1 className={classes.loading}>Initializing Repos...</h1>
) : (
<Container style={{ padding: 10 }}>
{!data ? (
<div style={{ placeItems: "center" }}>Loading...</div>
) : (
<Grid container alignItems='center' spacing={4}>
{data &&
data
.filter((data) => {
if (formData.language === "All") return true
return data.language === formData.language
})
.filter((data) => {
if (formData.search === "") return true
return (data.name + data.language)
.toLowerCase()
.includes(formData.search.toLowerCase())
})
.map((user) => <RepoCard key={user.id} user={user} />)}
</Grid>
)}
</Container>
)}
<Button
variant='contained'
color='primary'
disableElevation
style={{
borderRadius: 0,
display: "block",
marginLeft: "auto",
marginRight: "auto",
position: "relative",
marginTop: "80px"
}}
>
Back to Top
</Button>
</div>
</>
)
}
export default Profile
You can use flex and space-around feature. like below:
<div class="container">
<div>
your items
</div>
<Button
variant='contained'
color='primary'
disableElevation
style={{
borderRadius: 0,
elevation: "disabled",
display: "block",
marginLeft: "auto",
marginRight: "auto",
marginTop: "80px",
}}
>
Back to Top
</Button>
</div>
Style:
.container{
display: flex;
flex-direction:column;
justify-content: space-between;
}
Using this you split your content to two part.
First part which will be your array items will be shown at the top.
The second part which is your button will be shown at the bottom.
This is because your making a space between first part and second part by using space-around of justify-content.
without sticky or fixed the only thing i can think of is using position: absolute; and bottom: 0; or placing them in a container with some combination of the same, then positioning it as needed. same as Joeri in the comments, would need a bit more context to help :) good luck!
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}
In my React-Native app I have an icon and SearchBar in my header (from react navigation).
The following code:
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle:
<View style={{ flex: 1, flexDirection: "row", paddingHorizontal: 15, alignItems: "center" }}>
<StatusBar default style={{ flex: 1, height: getStatusBarHeight() }} />
<Icon name="chevron-left" size={28} />
<SearchBar round platform={"default"} placeholder="Search" containerStyle={{
flex: 1, backgroundColor: "transparent"
}} />
</View>,
headerStyle: {
backgroundColor: '#e54b4d',
}
};
}
outputs this:
So far so good. However, I want to have padding below the SearchBar. In other words, I want to have the distance from the top of the screen to the SearchBar as a padding below the SearchBar. (I can obtain the distance value using getStatusBarHeight() from rn-status-bar-height)
However, if I put paddingBottom: getStatusBarHeight() to the headerStyle, I get this result:
Basically, now I have the padding that I wanted, however, the StatusBar overlaps with the SearchBar.
How can I put paddingBottom without making the StatusBar and SearchBar overlap?
To change the padding of the header in your case you'll need to change headerTitleContainerStyle and not headerTitle.
For example :
headerTitleContainerStyle: { paddingVertical: 10 }
You can still check the doc.
For ios you will need to set backgroundColor.Below code is fit for android ios both.Hope it helps you.
import React, { Component } from 'react';
import { getStatusBarHeight } from 'react-native-status-bar-height';
import {
Modal,
Button,
View,
Text,
StyleSheet,
StatusBar,
Image,
Platform,
} from 'react-native';
import { SearchBar, Icon } from 'react-native-elements';
export default class AssetExample extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle: (
<View
style={{
flex: 1,
backgroundColor: Platform.OS === 'ios' ? '#e54b4d' : '',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 10,
height: StatusBar.currentHeight,
}}>
<Icon name="chevron-left" size={28} />
<SearchBar
round
platform={'default'}
placeholder="Search"
containerStyle={{
flex: 1,
backgroundColor: 'transparent',
}}
/>
</View>
),
headerStyle: {
backgroundColor: '#e54b4d',
},
};
};
render() {
return (
<View style={styles.container}>
<Text>Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});
when i checked your code on my device its properly viewing with padding.
I have a problem styling with FlexBox.
In my code below, there is a listview with section headers. Each section header has items under it.
The problem is, all items are shown in one row. How can I fix it? I tried adding width 100% for each row but it didn't work.
Thanks in Advance!
var styles = StyleSheet.create({
// Default Loading View
loading: {
alignItems: 'center',
backgroundColor: '#FFFFFF',
flex: 1,
//fontFamily: 'Rokkitt',
justifyContent: 'center',
padding: 5,
paddingTop: 40,
},
// Table
listView: {
backgroundColor: '#FFFFFF',
paddingTop: 60,
},
// Table Row
rowContainer: {
flexDirection: 'row',
padding: 20,
},
// Text wrapper within row
textContainer: {
flex: 1
},
// Row separator
separator: {
height: 1,
backgroundColor: '#E3E0D7'
},
// Row Post Title
title: {
color: '#3D728E',
//fontFamily: 'Rokkitt',
fontSize: 20,
},
// Row Post Description
description: {
color: '#7C705F',
//fontFamily: 'Josefin Sans',
fontSize: 14,
lineHeight: 20,
marginTop: 8,
textAlign: 'left',
},
});
class Courses extends Component {
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<View style={{
flex: 1
}}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
style={styles.listView}
/>
</View>
);
}
renderRow(data) {
var rowPress = () => {
console.log('row pressed');
};
var header = (
<View>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Text style={styles.title}>{data.nid}</Text>
<Text style={styles.description} numberOfLines={0}>{data.title}</Text>
</View>
</View>
<View style={styles.separator}></View>
</View>
);
///////////
var content = [];
for(var x=0; x < Object.keys(data.course).length; x++){
content.push(
<TouchableHighlight
underlayColor='#e3e0d7'
key={x}
onPress={rowPress()}
>
<Text style={{
flex: 1,
flexDirection: 'column',
flexWrap: 'wrap',
}}>{data.course[x].title}</Text>
</TouchableHighlight>
);
}
var clist = (
<View style={styles.rowContainer}>
{content}
</View>
);
////////////
return (
<Accordion
header={header}
content={clist} //// <<< Problem! contents are shown in one line, i need each item to wrap whole line>>>
easing="easeOutCubic"
/>
);
}
renderLoadingView() {
return (
<View style={styles.loading}>
<Text style={styles.loading}>
Fetching Courses, please wait...
</Text>
</View>
);
}
}
Below are a couple of general CSS / Flexbox concepts that may help identify the problem.
In standard CSS, the initial value of flex-direction is row. This means that items will line up horizontally. For vertical alignment, override the default with flex-direction: column.
However, in React Native, the default flex-direction is column.
https://facebook.github.io/react-native/docs/flexbox.html#flex-direction
Note that when you switch flex-direction, keyword alignment properties such as align-items and justify-content, switch directions, as well.
Another flexbox initial setting (in both CSS and React) is flex-wrap: nowrap.
This means items will remain in a single line.
To create a multi-line flex container, override the default with flex-wrap: wrap.