Material UI dropdown/autocomplete - css

When trying to put a label with a dropdown in material UI for some reason I am seeing this behavior
For some reason I can't make them aligned at the same row.
This is my component:
const useStyles = makeStyles(theme => ({
root: {
justifyContent: 'center',
display: 'flex',
},
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
function DutPreferencesTab(props) {
const classes = useStyles()
const {data} = props
console.log(data)
const [age, setAge] = React.useState('');
const handleChange = (event) => {
setAge(event.target.value);
};
return (
<div style={{display: 'flex', direction: 'row'}}>
<CustomLabel text={'Relay:'} variant={"subtitle1"} />
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={handleChange}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</div>
)
}
CustomLabel.js
import React from 'react'
import Typography from '#material-ui/core/Typography';
import clsx from 'clsx';
function CustomLabel({text, variant, styles}) {
return (
<div className={clsx(styles)}>
<Typography variant={variant} gutterBottom>
{text}
</Typography>
</div>
)
}
export default CustomLabel
I tried everything but still I can't make them align at the same row and I can't figure our why. It appears to only happen with dropdowns as far as I saw. I have other texts that are perfectly aligned with the label.
Am I missing something?

If you highlight the elements in dev tools, you will see that they are aligned. The problem is just that the Select is much taller than the label and by default the tops of the elements are aligned (actually the elements are stretched to be the same height, but this has the effect of lining them up at the top).
When you select an item and the label in the Select (e.g. "Age") moves up, you can more easily see why it is so tall.
The solution is to modify the align-items CSS property on the div that wraps the label and the select. A value of baseline seems to be the best option in this case.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import FormControl from "#material-ui/core/FormControl";
import InputLabel from "#material-ui/core/InputLabel";
import Select from "#material-ui/core/Select";
import MenuItem from "#material-ui/core/MenuItem";
import CustomLabel from "./CustomLabel";
const useStyles = makeStyles((theme) => ({
root: {
alignItems: "baseline",
display: "flex"
},
formControl: {
margin: theme.spacing(1),
minWidth: 120
}
}));
export default function DutPreferencesTab(props) {
const classes = useStyles();
const [age, setAge] = React.useState("");
const handleChange = (event) => {
setAge(event.target.value);
};
return (
<div className={classes.root}>
<CustomLabel text={"Relay:"} variant={"subtitle1"} />
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={handleChange}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</div>
);
}
Related Flexbox resource: https://css-tricks.com/snippets/css/a-guide-to-flexbox/#align-items

Related

Reactjs material ui Select item inside dialog with weird style

I am trying to create a "Dialog" box which contain a "Select" inside it.
As you can see from image "Select" component is showing item so weird!
I tried to style the items but I couldn't find the way to show item regular (Vertical items with white background color and black foreground color).
I have to mention that I copied the exact code in material ui website for "Dialog" and
"Select"
When I use "Select" inside "Dialog" this weird style happen.
This is my code:
import React, {useState} from 'react';
import {makeStyles, withStyles} from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import MuiDialogTitle from '#material-ui/core/DialogTitle';
import MuiDialogContent from '#material-ui/core/DialogContent';
import MuiDialogActions from '#material-ui/core/DialogActions';
import IconButton from '#material-ui/core/IconButton';
import CloseIcon from '#material-ui/icons/Close';
import Typography from '#material-ui/core/Typography';
import Card from "#material-ui/core/Card";
import CardActionArea from "#material-ui/core/CardActionArea";
import CardMedia from "#material-ui/core/CardMedia";
import CardContent from "#material-ui/core/CardContent";
import CardActions from "#material-ui/core/CardActions";
import {Col, Row} from "react-bootstrap";
import {FormControl, InputLabel, MenuItem, Select, TextField} from "#material-ui/core";
const styles = (theme) => ({
root: {
margin: 0,
padding: theme.spacing(2),
},
closeButton: {
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
});
const DialogTitle = withStyles(styles)((props) => {
const { children, classes, onClose, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton aria-label="close" className={classes.closeButton} onClick={onClose}>
<CloseIcon />
</IconButton>
) : null}
</MuiDialogTitle>
);
});
const DialogContent = withStyles((theme) => ({
root: {
padding: theme.spacing(2),
},
}))(MuiDialogContent);
const DialogActions = withStyles((theme) => ({
root: {
margin: 0,
padding: theme.spacing(1),
},
}))(MuiDialogActions);
export default function SdWanDialog(props) {
const {
status,
handleClose,
company
} = props;
const useStyles2 = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 185,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
const classes2 = useStyles2();
const [subnet, setSubnet] = useState('');
const handleChange = (event) => {
setSubnet(event.target.value);
};
return (
<div>
{/*<Button variant="outlined" color="primary" onClick={handleClickOpen}>*/}
{/* Open dialog*/}
{/*</Button>*/}
<Dialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={status}>
<DialogTitle id="customized-dialog-title" onClose={handleClose}>
TITLE
</DialogTitle>
<DialogContent >
<Row>
<Col>
<FormControl variant="outlined">
<InputLabel id="select-label">Subnet</InputLabel>
<Select
labelId="select-label"
id="select-id"
value={subnet}
onChange={handleChange}
label="Subnet"
>
<MenuItem value=""><em>None</em></MenuItem>
<MenuItem value={'value1'}>value1</MenuItem>
<MenuItem value={'value2'}>value2</MenuItem>
<MenuItem value={'value3'}>value3</MenuItem>
</Select>
<br/>
<TextField
id="branchName"
label="Branch name"
variant="outlined"
color="primary"
/>
</FormControl>
</Col>
</Row>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} variant="contained" color="primary">
Save changes
</Button>
</DialogActions>
</Dialog>
</div>
);
}

How to disable some options in "Select" component of Material-UI like in "Autocomplete"?

is there is any way to disable some options in the Select component like in Autocomplete
PS: the option is in an array
<FormControl variant="outlined">
<InputLabel>States</InputLabel>
<Select native
defaultValue=""
// value={value}
onChange={inputEvent}
label="States"
>
{fetchedStates.map((states, i) => (
<option key={states + i} value={states}>
{states}
</option>
))}
</Select>
</FormControl>
The way to do this for Select is to add the disabled property to the MenuItem (shown for the "Twenty" MenuItem in the example below).
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState("");
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="demo-simple-select-outlined-label">Age</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
label="Age"
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem disabled value={20}>
Twenty
</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</div>
);
}
For a native Select, you instead use the disabled prop for <option>:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState("");
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="demo-simple-select-outlined-label">Age</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
label="Age"
native
>
<option aria-label="None" value="" />
<option value={10}>Ten</option>
<option disabled value={20}>
Twenty
</option>
<option value={30}>Thirty</option>
</Select>
</FormControl>
</div>
);
}
If the options are in an array, you just need to have some way of determining which options should be disabled. The example below shows one way of doing this where the option data contains whether or not the option should be disabled.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
const options = [
{ value: 10, label: "Ten" },
{ value: 20, label: "Twenty", disabled: true },
{ value: 30, label: "Thirty" }
];
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState("");
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="demo-simple-select-outlined-label">Age</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
label="Age"
native
>
<option aria-label="None" value="" />
{options.map(option => (
<option value={option.value} disabled={option.disabled}>
{option.label}
</option>
))}
</Select>
</FormControl>
</div>
);
}

Extra Line coming inside Textfield component of material-ui with outlined borders

I am trying to use Textfield component of material ui package. I am using variant="outlined" property of it. But inside that Textfield line is also coming so looks bad from ui prespective.
Any idea how to show only ouline boundary.
(source: imggmi.com)
I guess Textfield by default puts that line. Its is the line just below Phone*.
import React, { Component } from "react";
import { connect } from "react-redux";
import { signIn } from "../../store/actions/authActions";
import { trySignUp } from "../../store/actions/authActions";
import { Redirect } from "react-router-dom";
import Container from "#material-ui/core/Container";
import CssBaseline from "#material-ui/core/CssBaseline";
import Avatar from "#material-ui/core/Avatar";
import Typography from "#material-ui/core/Typography";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import { withStyles } from "#material-ui/styles";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
class SignIn extends Component {
render() {
const { authError, auth, classes } = this.props;
if (auth.uid) return <Redirect to="/" />;
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form onSubmit={this.handleSubmit} className={classes.form}>
{!this.state.isOTPSent && (
<TextField
variant="outlined"
margin="normal"
required
fullWidth
type="tel"
id="phone"
label="Phone"
name="phone"
autoComplete="phone"
autoFocus
onChange={this.handleChange}
/>
)}
{this.state.isOTPSent && (
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="otp"
label="OTP"
name="otp"
autoFocus
onChange={this.handleChange}
/>
)}
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<div className="input-field">
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
id="loginButtonId"
onClick={this.state.isOTPSent ? this.handleSubmit : null}
className={classes.submit}
>
{this.state.isOTPSent ? "Login" : "Get OTP"}
</Button>
<div className="red-text center">
{authError ? <p>{authError}</p> : null}
</div>
</div>
</form>
</div>
</Container>
);
}
}
const styles = theme => ({
"#global": {
body: {
backgroundColor: "white"
}
},
paper: {
marginTop: 50,
display: "flex",
flexDirection: "column",
alignItems: "center"
},
avatar: {
margin: 1,
backgroundColor: "red"
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: 1
},
submit: {
margin: (3, 0, 2)
}
});
const mapStateToProps = state => {
return {
authError: state.auth.authError,
auth: state.firebase.auth
};
};
const mapDispatchToProps = dispatch => {
return {
signIn: phoneNumber => dispatch(signIn(phoneNumber)),
trySignUp: () => dispatch(trySignUp())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withStyles(styles)(SignIn));
Need to remove the line.

Material-UI How to set minWidth and maxWidth of MenuItem (popover) according to the width of the select component

The width of the popover, to be precise. No matter how long the text of menu item is, I want the width of the popover always the same as the select component. Set the autoWidth to true or false is not helping.
following are code for the select component:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import OutlinedInput from '#material-ui/core/OutlinedInput';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
}));
function SimpleSelect() {
const classes = useStyles();
const [values, setValues] = React.useState({
age: '',
});
const inputLabel = React.useRef(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current.offsetWidth);
}, []);
function handleChange(event) {
setValues(oldValues => ({
...oldValues,
[event.target.name]: event.target.value,
}));
}
return (
<form className={classes.root} autoComplete="off">
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} htmlFor="outlined-age-simple">
Age
</InputLabel>
<Select
value={values.age}
onChange={handleChange}
input={<OutlinedInput labelWidth={labelWidth} name="age" id="outlined-age-simple" />}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
export default SimpleSelect;
How can I achive this?
You can achieve this by setting an explicit width on the menu items that is the same as the width for the form control.
Below is an example:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import MuiMenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const selectWidth = 150;
const useStyles = makeStyles(theme => ({
root: {
display: "flex",
flexWrap: "wrap"
},
formControl: {
margin: theme.spacing(1),
width: selectWidth
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
const useMenuItemStyles = makeStyles(theme => ({
menuItem: {
width: selectWidth
}
}));
function MenuItem(props) {
const classes = useMenuItemStyles(props);
return <MuiMenuItem className={classes.menuItem} {...props} />;
}
function SimpleSelect() {
const classes = useStyles();
const [values, setValues] = React.useState({
age: ""
});
function handleChange(event) {
setValues(oldValues => ({
...oldValues,
[event.target.name]: event.target.value
}));
}
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={values.age}
onChange={handleChange}
inputProps={{
name: "age",
id: "age-simple"
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
export default SimpleSelect;
If you want the width of the Select to be dynamic based on the width of the widest menu item, then the solution is a fair amount more complicated.
Menu by default have auto width and height
menu adjust it's width and height according to child ListItems
const useStyles = makeStyles((theme: Theme) =>
createStyles({
listItem:{
maxWidth:150,
minWidth:100,
padding: theme.spacing(2)
}
}),
);

How to make Select menu location relative to controller button in React?

I want to implement a <Select /> component with two features.
I want to hide the form control. As shown in Fig. 1. I am currently accomplishing this by using display: 'none'. CodeSandbox Demo
I want to make the select menu appear directly under the button that opens the menu. As shown in Fig. 2. Currently, it seems to be positioned absolutely in the upper left of the window. CodeSandbox Demo
How can I accomplish both of these features? (A code sandbox demo of your answer would be most helpful.)
Fig. 1. Form control is hidden
https://codesandbox.io/s/j7xr2wmw7v
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import Button from "#material-ui/core/Button";
const styles = theme => ({
button: {
display: "block",
marginTop: theme.spacing.unit * 30
},
formControl: {
margin: theme.spacing.unit,
minWidth: 120,
display: "none"
}
});
class ControlledOpenSelect extends React.Component {
state = {
age: "",
open: false
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
handleClose = () => {
this.setState({ open: false });
};
handleOpen = () => {
this.setState({ open: true });
};
render() {
const { classes } = this.props;
return (
<form autoComplete="off">
<Button className={classes.button} onClick={this.handleOpen}>
Open the select
</Button>
<FormControl hidden className={classes.formControl}>
<InputLabel htmlFor="demo-controlled-open-select">Age</InputLabel>
<Select
open={this.state.open}
onClose={this.handleClose}
onOpen={this.handleOpen}
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: "age",
id: "demo-controlled-open-select"
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
}
ControlledOpenSelect.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(ControlledOpenSelect);
Fig. 2. Dropdown select menu appears directly beneath button
https://codesandbox.io/s/l4k8p7zxjq
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
import Button from '#material-ui/core/Button';
const styles = theme => ({
button: {
display: 'block',
marginTop: theme.spacing.unit * 2,
},
formControl: {
margin: theme.spacing.unit,
minWidth: 120,
},
});
class ControlledOpenSelect extends React.Component {
state = {
age: '',
open: false,
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
handleClose = () => {
this.setState({ open: false });
};
handleOpen = () => {
this.setState({ open: true });
};
render() {
const { classes } = this.props;
return (
<form autoComplete="off">
<Button className={classes.button} onClick={this.handleOpen}>
Open the select
</Button>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="demo-controlled-open-select">Age</InputLabel>
<Select
open={this.state.open}
onClose={this.handleClose}
onOpen={this.handleOpen}
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: 'age',
id: 'demo-controlled-open-select',
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
}
ControlledOpenSelect.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(ControlledOpenSelect);
instead of
display: "none"
try
visibility: "hidden",
width:'0',
height:'0'
this will leave the container element in place and allow the dropdown to appear in the correct position

Resources