How to reduce the padding of TextField used as Select of muiv5. And Also the max-height of dropdown option plus the padding of individual list item of that dropdown.
I can't wrap my head around sx prop. Can someone please help me understand how to override styles uisng sx props. Thanks in advance.
const pageList = useMemo(() => {
return range(1, 100).map((item, i) => {
return (
<MenuItem
key={i}
value={item}
sx={{
'& .MuiMenuItem-root.Mui-selected': {
padding: '0px 40%',
},
}}
>
{item}
</MenuItem>
);
});
}, [lastPage]);
<TextField
InputLabelProps={{ shrink: false }}
margin="dense"
variant="outlined"
size="small"
select
value={currentPage}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) : 0;
onPageChange(page);
}}
sx={{
'&.MuiInputBase-input': {
padding: '10px',
},
'&.MuiList-root': {
maxHeight: '100px',
},
}}
>
{pageList}
</TextField>
I only want to show the text of the tab on selection.
This is from the MUI documentation. How can I only show labels on selection? I assume I can use the state below and translate it somehow, how on the selection the color appears with the element.
Please see the code where I have tried to establish. I am new to this framework. If anyone can provide tips let me know!
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`vertical-tabpanel-${index}`}
aria-labelledby={`vertical-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
};
function a11yProps(index) {
return {
id: `vertical-tab-${index}`,
'aria-controls': `vertical-tabpanel-${index}`,
};
}
//
const JobPostBuild = () => {
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Box
sx={{ flexGrow: 1, bgcolor: 'gray', display: 'flex', height: 500 }}
>
<Tabs
orientation="vertical"
variant="scrollable"
centered
value={value}
onChange={handleChange}
sx={{ borderRight: 1, borderColor: 'divider' }}
>
<Tab icon={<WorkIcon/>} label={"Role"} {...a11yProps(0)} />
<Tab icon={<AccountBoxIcon/>} label="People" {...a11yProps(1)} />
<Tab icon={<ViewCompactIcon/>} label="Build" {...a11yProps(2)} />
<Tab icon={<PostAddIcon/>} label="Post" {...a11yProps(3)} />
</Tabs>
<TabPanel value={value} index={0}>
Role
</TabPanel>
<TabPanel value={value} index={1}>
People
</TabPanel>
<TabPanel value={value} index={2}>
Build
</TabPanel>
<TabPanel value={value} index={3}>
Post
</TabPanel>
</Box>
);
}
export default JobPostBuild
Happy to discuss this over Discord please let me know!
You can check the value of selected tab to set a condition for displaying tab label:
<Tab label={value === 0 ? "Role" : ""} {...a11yProps(0)} />
Demo
I was able to make it so that the search bar stays to the right of the search bar. Not mandatory of course. I can be inside the right side of the search bar. This is the gitHub link for this: https://github.com/strawberries73/telescope/tree/Issue-1226
What I did try was an InputAdornment method. https://material-ui.com/components/text-fields/#input-adornments. This code can be found here: https://github.com/strawberries73/telescope/tree/Issue-1225
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import PropTypes from 'prop-types';
import SearchIcon from '#material-ui/icons/Search';
import {
Grid,
MenuItem,
TextField,
FormControl,
Paper,
IconButton,
Box,
Typography,
Fab,
} from '#material-ui/core';
const useStyles = makeStyles((theme) => ({
root: {
overflow: 'visible',
maxWidth: '785px',
padding: 0,
marginTop: '10rem',
marginLeft: 'auto',
marginRight: 'auto',
},
card: {
padding: theme.spacing(2, 4, 2, 4),
backgroundColor: theme.palette.background.default,
},
input: {
fontSize: '1.6rem',
'& > *': {
fontSize: '1.6rem !important',
color: theme.palette.text.default,
},
},
header: {
padding: 0,
marginBottom: theme.spacing(2),
backgroundColor: theme.palette.primary.main,
},
h1: {
display: 'block',
transition: 'all linear 350ms',
fontWeight: 600,
color: theme.palette.text.secondary,
[theme.breakpoints.between('xs', 'sm')]: {
fontSize: '3rem',
},
[theme.breakpoints.between('md', 'lg')]: {
fontSize: '4rem',
},
[theme.breakpoints.up('xl')]: {
fontSize: '5rem',
},
},
iconButton: {
backgroundColor: theme.palette.secondary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
},
'& * > .MuiSvgIcon-root': {
fontSize: '2rem',
color: theme.palette.text.primary,
},
margin: 0,
marginRight: theme.spacing(-1.45),
bottom: theme.spacing(-2),
float: 'right',
marginBottom: theme.spacing(-5.5),
[theme.breakpoints.only('xs')]: {
marginTop: theme.spacing(6),
marginRight: theme.spacing(-8),
},
},
selectControl: {
'& > *': {
fontSize: '1.2rem',
textTransform: 'capitalize',
color: theme.palette.primary.main,
},
},
selectItem: {
fontSize: '1.4rem',
textTransform: 'capitalize',
color: theme.palette.primary.main,
},
}));
function CustomizedInputBase(props) {
const classes = useStyles();
const { searchText, onChangeHandler, onFilterChangeHandler, filter, onFormSubmit } = props;
const onFilterChange = (event) => {
onFilterChangeHandler(event.target.value);
};
const onTextChange = (event) => {
onChangeHandler(event.target.value);
};
const onSubmit = (event) => {
event.preventDefault();
onFormSubmit();
};
const searchOptions = ['post', 'author'];
return (
<Box className={classes.root} boxShadow={2}>
<Paper component="form" className={classes.card} elevation={0}>
<Grid
container
className={classes.header}
direction="row"
spacing={8}
alignItems="center"
justify="flex-start"
>
<Grid item xs={12}>
<Typography variant="h1" className={classes.h1}>
Search
</Typography>
</Grid>
</Grid>
<Fab size="large" className={classes.iconButton}>
<FormControl>
<IconButton type="submit" onClick={(event) => onSubmit(event)} aria-label="search">
<SearchIcon />
</IconButton>
</FormControl>
</Fab>
<Grid container direction="row" spacing={2} alignItems="center" justify="flex-start">
<Grid item xs={12} sm={2} lg={2}>
<FormControl fullWidth={true}>
<TextField
id="standard-select-search-type"
select
label="Filter"
value={filter}
variant="outlined"
className={classes.selectControl}
onChange={(event) => onFilterChange(event)}
>
{searchOptions.map((option) => (
<MenuItem key={option} value={option} className={classes.selectItem}>
{option}
</MenuItem>
))}
</TextField>
</FormControl>
</Grid>
<Grid item xs={12} sm={10} lg={10}>
<FormControl fullWidth={true}>
<TextField
className={classes.input}
placeholder="How to Get Started in Open Source"
inputProps={{ 'aria-label': 'search telescope' }}
variant="outlined"
value={searchText}
onChange={(event) => onTextChange(event)}
/>
</FormControl>
</Grid>
</Grid>
</Paper>
</Box>
);
}
CustomizedInputBase.propTypes = {
searchText: PropTypes.string,
onChangeHandler: PropTypes.func,
onFilterChangeHandler: PropTypes.func,
onFormSubmit: PropTypes.func,
filter: PropTypes.string,
};
export default CustomizedInputBase;
Solved! My solution to my answer.
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '#material-ui/core/styles';
import SearchIcon from '#material-ui/icons/Search';
import InputAdornment from '#material-ui/core/InputAdornment';
import {
Grid,
MenuItem,
TextField,
FormControl,
Paper,
IconButton,
Box,
Typography,
} from '#material-ui/core';
import SearchHelp from '../SearchHelp';
const useStyles = makeStyles((theme) => ({
root: {
overflow: 'visible',
maxWidth: '785px',
padding: 0,
marginTop: '10rem',
marginLeft: 'auto',
marginRight: 'auto',
marginBottom: theme.spacing(6),
},
card: {
padding: theme.spacing(2, 4, 2, 4),
backgroundColor: theme.palette.background.default,
},
header: {
padding: 0,
marginBottom: theme.spacing(2),
backgroundColor: theme.palette.primary.main,
},
h1: {
display: 'block',
transition: 'all linear 350ms',
fontWeight: 600,
color: theme.palette.text.secondary,
[theme.breakpoints.between('xs', 'sm')]: {
fontSize: '3rem',
},
[theme.breakpoints.between('md', 'lg')]: {
fontSize: '4rem',
},
[theme.breakpoints.up('xl')]: {
fontSize: '5rem',
},
},
iconButton: {
backgroundColor: theme.palette.secondary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
},
'& * > .MuiSvgIcon-root': {
fontSize: '2rem',
color: theme.palette.primary.contrastText,
},
margin: 0,
position: 'relative',
bottom: theme.spacing(6),
float: 'right',
marginBottom: theme.spacing(-12),
},
selectControl: {
'& > *': {
fontSize: '1.2rem',
textTransform: 'capitalize',
color: theme.palette.primary.main,
},
},
selectItem: {
fontSize: '1.4rem',
textTransform: 'capitalize',
color: theme.palette.primary.main,
},
}));
function CustomizedInputBase(props) {
const classes = useStyles();
const { text, onTextChange, onFilterChange, filter, onSubmit } = props;
const searchOptions = ['post', 'author'];
return (
<Box className={classes.root} boxShadow={2}>
<Paper component="form" className={classes.card} elevation={0}>
<Grid
container
className={classes.header}
direction="row"
spacing={8}
alignItems="center"
justify="flex-start"
>
<Grid item>
<Typography variant="h1" className={classes.h1}>
Search
</Typography>
</Grid>
<SearchHelp />
</Grid>
<Grid container direction="row" spacing={2} alignItems="center" justify="flex-start">
<Grid item xs={12} sm={2} lg={2}>
<FormControl fullWidth={true}>
<TextField
id="standard-select-search-type"
select
label="Filter"
value={filter}
variant="outlined"
className={classes.selectControl}
onChange={(event) => onFilterChange(event.target.value)}
>
{searchOptions.map((option) => (
<MenuItem key={option} value={option} className={classes.selectItem}>
{option}
</MenuItem>
))}
</TextField>
</FormControl>
</Grid>
<Grid item xs={12} sm={10} lg={10}>
<FormControl fullWidth={true}>
<TextField
className={classes.input}
placeholder="How to Get Started in Open Source"
inputProps={{ 'aria-label': 'search telescope' }}
variant="outlined"
value={text}
InputProps={{
endAdornment: (
<InputAdornment>
<IconButton type="submit" className={classes.iconButton} onClick={onSubmit}>
<SearchIcon />
</IconButton>
</InputAdornment>
),
}}
onChange={(event) => onTextChange(event.target.value)}
/>
</FormControl>
</Grid>
</Grid>
</Paper>
</Box>
);
}
CustomizedInputBase.propTypes = {
text: PropTypes.string,
onTextChange: PropTypes.func,
filter: PropTypes.string,
onFilterChange: PropTypes.func,
onSubmit: PropTypes.func,
};
export default CustomizedInputBase;
In my React application, I have a Navigation bar where in there are multiple Tabs, which are created with the use of Marerial UI's AppBar, Tabs and Tab component (in sequence), as below:
function associatedProps(index) {
return {
id: `nav-tab-${index}`,
'aria-controls': `nav-tabpanel-${index}`
};
}
function LinkTab(props) {
const history = useHistory();
const route = props.route;
console.log(props);
return (
<>
<Tab
component="a"
onClick={(event) => {
event.preventDefault();
history.push(route)
}}
{...props}
/>
</>
);
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
height: theme.navBarHeight
},
tabIndicator: {
backgroundColor: PRIMARY_RED.default
},
tabBar: {
top: '80px'
}
}));
export default function NavTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="fixed" className={classes.tabBar}>
<Tabs
variant=""
classes={{indicator: classes.tabIndicator}}
value={value}
onChange={handleChange}
aria-label="nav tabs example"
>
<LinkTab {...PRIMARY_NAVIGATION.MY_LIST} {...associatedProps(0)} />
<LinkTab {...PRIMARY_NAVIGATION.MY_REQUESTS} {...associatedProps(1)} />
<LinkTab {...PRIMARY_NAVIGATION.REPORT} {...associatedProps(2)} />
</Tabs>
</AppBar>
</div>
);
}
Now herein this setup I wanted my REPORT tab to be aligned right of the App Bar. I do not see any CSS Rule or Prop which in Documentation, which can help me here.
Please suggest how can I achieve this in current setup.
You should set a class for Tabs like this:
const useStyles = makeStyles((theme) => ({
tabs: {
'&:last-child': {
position: 'absolute',
right: '0'
}
}
}));
export default function NavTabs() {
...
return (
<div className={classes.root}>
<AppBar position="fixed" className={classes.tabBar}>
<Tabs
variant=""
classes={classes.tabs}
value={value}
onChange={handleChange}
aria-label="nav tabs example"
>
<LinkTab {...PRIMARY_NAVIGATION.MY_LIST} {...associatedProps(0)} />
<LinkTab {...PRIMARY_NAVIGATION.MY_REQUESTS} {...associatedProps(1)} />
<LinkTab {...PRIMARY_NAVIGATION.REPORT} {...associatedProps(2)} />
</Tabs>
</AppBar>
</div>
);
Tabs do not provide a property to align a specific item to the start or end. But you can leverage css to achieve your result.
Add a className to the item to be right aligned and define a marginLeft property on it
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
height: theme.navBarHeight
},
tabIndicator: {
backgroundColor: PRIMARY_RED.default
},
tabBar: {
top: '80px'
},
rightAlign: {
marginLeft: 'auto',
}
}));
export default function NavTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="fixed" className={classes.tabBar}>
<Tabs
variant=""
classes={{indicator: classes.tabIndicator}}
value={value}
onChange={handleChange}
aria-label="nav tabs example"
>
<LinkTab {...PRIMARY_NAVIGATION.MY_LIST} {...associatedProps(0)} />
<LinkTab {...PRIMARY_NAVIGATION.MY_REQUESTS} {...associatedProps(1)} />
<LinkTab {...PRIMARY_NAVIGATION.REPORT} {...associatedProps(2)} className={classes.rightAlign}/>
</Tabs>
</AppBar>
</div>
);
}
Sample working demo
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!