Material UI Select component not displaying properly - reactjs

I have created a simple select component with menu items (material ui v 4.12). But the select component is being displayed entirely wrong. There are no console errors. What might be wrong here?
Here is the screenshot and the code.
import React, { useState } from "react";
import FormControl from "#material-ui/core/FormControl";
import InputLabel from "#material-ui/core/InputLabel";
import Select from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import { makeStyles } from "#material-ui/core";
const mockData = ["list01", "list02"];
function TestPage() {
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
const classes = useStyles();
const [data, setData] = useState("");
return (
<div className="test">
<h2>TEST</h2>
<FormControl
variant="outlined"
classes={{
root: classes.formControl,
}}
>
<InputLabel id="demo-simple-select-outlined-label">
Select list
</InputLabel>
<Select
id="test-select-outlined"
value={data}
onChange={(e) => setData(e.target.value)}
label="Select list"
>
{mockData.map((item, index) => (
<MenuItem key={index + 1} value={item}>
{item}
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
export default TestPage;

Your Select import is wrong:
import Select from "#material-ui/core/InputLabel";
just change it to:
import Select from "#material-ui/core/Select";

Related

How do I use an SVG as an IconComponent in a Material UI Select?

I have
import CaretDownIcon from 'src/../public/images/svg/caret-down.svg';
<Select
className={selectClassName}
data-testid={testId}
// IconComponent={<SvgIcon>{CaretDownIcon}</SvgIcon>}
// IconComponent={CaretDownIcon}
inputProps={{
name,
id: labelId,
}}
{...rest}
>
I tried both of those commented lines, but no dice. What's the right way?
You need to create a component for your custom svg icon. Copy the path from the svg file to make a component as shown below:
function CustomSvgIcon(props) {
return (
<SvgIcon {...props}>
<path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
</SvgIcon>
);
}
then you can use that with IconComponent={CustomSvgIcon}.
Here's a full working example:
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 SvgIcon from "#material-ui/core/SvgIcon";
const styles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap"
},
formControl: {
margin: theme.spacing.unit,
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing.unit * 2
}
});
function CustomSvgIcon(props) {
return (
<SvgIcon {...props}>
<path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
</SvgIcon>
);
}
class SimpleSelect extends React.Component {
state = {
age: "",
name: "hai"
};
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const { classes } = this.props;
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: "age",
id: "age-simple"
}}
IconComponent={CustomSvgIcon}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
}
SimpleSelect.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(SimpleSelect);
It is also possible to create a React component from an imported SVG file, but this is dependent on your build configuration. If you are using create-react-app then this will work (see this article for details).
Below is an example using the import approach. This uses import { ReactComponent as TestSvgAsComponent } from "./test.svg"; to get a React component from the SVG file. The other step necessary is to add in the styles that would be applied by SvgIcon (classes.icon from useIconStyles in the example).
import React from "react";
import PropTypes from "prop-types";
import { withStyles, 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";
import { ReactComponent as TestSvgAsComponent } from "./test.svg";
import clsx from "clsx";
const styles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap"
},
formControl: {
margin: theme.spacing.unit,
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing.unit * 2
}
});
const useIconStyles = makeStyles({
// This is a copy of the styles from https://github.com/mui-org/material-ui/blob/v4.12.3/packages/material-ui/src/SvgIcon/SvgIcon.js#L10
icon: {
fill: "currentColor",
width: "1em",
height: "1em",
display: "inline-block",
fontSize: "1.5rem",
transition: "fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
flexShrink: 0,
userSelect: "none"
}
});
function CustomSvgIcon({ className, ...other }) {
const classes = useIconStyles();
return (
<TestSvgAsComponent className={clsx(classes.icon, className)} {...other} />
);
}
class SimpleSelect extends React.Component {
state = {
age: "",
name: "hai"
};
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const { classes } = this.props;
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: "age",
id: "age-simple"
}}
IconComponent={CustomSvgIcon}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
}
SimpleSelect.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(SimpleSelect);
Related documentation:
https://material-ui.com/components/icons/#svgicon
Related answer:
Select is not working onClick IconComponent(dropdown-arrow) in react material ui

How to use material-ui inputBase to make select component?

I would like to make select dropdown using by InputBase component. The select box shows correctly, but dropdown options doesn't show when I click the field. I had tried other inputComponent like input, it's work fine.
I want the label above on the field and I know that I can use native select to make this. However, I want to share same styles between these components.
Does anyone know how to use input base to make select component?
The code provided below:
import React from "react";
import "./styles.css";
import {
FormControl,
InputLabel,
InputBase,
MenuItem
} from "#material-ui/core";
import { withStyles, fade } from "#material-ui/core/styles";
export default function App() {
const BootstrapInput = withStyles((theme) => ({
root: {
"label + &": {
marginTop: "20px"
}
},
input: {
position: "relative",
backgroundColor: theme.palette.common.white,
border: "1px solid #ccc",
fontSize: 14,
width: "380px",
height: "12px",
padding: "10px 12px",
transition: theme.transitions.create(["border-color", "box-shadow"]),
"&:focus": {
boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 0.2rem`,
borderColor: theme.palette.primary.main
}
}
}))(InputBase);
return (
<div className="App">
<FormControl>
<InputLabel shrink htmlFor="personalTitle">
Age
</InputLabel>
<BootstrapInput inputComponent="select" name="personalTitle">
<MenuItem>20</MenuItem>
<MenuItem>30</MenuItem>
<MenuItem>40</MenuItem>
</BootstrapInput>
</FormControl>
</div>
);
}
CodeSandbox link:
https://codesandbox.io/s/select-on-inputbase-0ufes?file=/src/App.js:0-1209
You Can use material-ui select component to manage select box easily. You can check more details using below link
https://material-ui.com/components/selects/
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 FormHelperText from '#material-ui/core/FormHelperText';
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 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>
)
}

How to style TextField in MaterialUI

I am using styled components.
I have
And this is fine expect one thing.. I want to style border-radius of that TextField
How can i do that?
import React from 'react';
import TextField from '#material-ui/core/TextField';
const Input = ({label}) => {
return (
<div>
<TextField style={{borderRadius: '90px'}} id="outlined-basic" label={label} variant="outlined" />
</div>
)
}
export default Input;
import React from "react";
import TextField from '#material-ui/core/TextField';
import { withStyles } from '#material-ui/core/styles';
const StyledTextField = withStyles({
root: {
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderRadius: `90px`,
},
},
},
})(TextField);
const Input = ({label}) => {
return (
<div>
<StyledTextField id="outlined-basic" label={label} variant="outlined" />
</div>
)
}
export default Input;

How to stylize material-ui select

I need to make a stylized version of material-ui select component.
What i have now is:
import { Select } from '#material-ui/core';
import type { SelectProps } from '#material-ui/core';
import styled from 'styled-components';
const menuProps = {
getContentAnchorEl: null,
anchorOrigin: {
vertical: "bottom",
horizontal: "left",
},
PopoverClasses: {
// pass only classnames
}
}
const StyledSelect = styled(Select)<SelectProps>`
... some styles
`;
const Select: React.FC<SelectProps> = (props) => {
return <StyledSelect MenuProps={menuProps} {...props}/>
};
I need to pass styles(NOT CLASSES) to popover part of Select to make a margin between popover and input.
I tried everything and found only way to pass classes to them.
But I can't use global classes o module classes because of project restrictions, only pass them in js.
Any ideas?
If you use the disablePortal: true menu prop, it will cause the Popover to be a descendant of the Select's root element in the DOM. This allows you to target it like the following:
const Select = styled(MuiSelect)`
.MuiPopover-paper {
margin-top: 3px;
}
`;
Here's a full working example:
import React from "react";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import MuiFormControl from "#material-ui/core/FormControl";
import MuiSelect from "#material-ui/core/Select";
import styled from "styled-components";
import { StylesProvider } from "#material-ui/core/styles";
const FormControl = styled(MuiFormControl)`
margin: 8px;
min-width: 120px;
`;
const Select = styled(MuiSelect)`
.MuiPopover-paper {
margin-top: 3px;
}
`;
export default function SimpleSelect() {
const [age, setAge] = React.useState("");
const handleChange = event => {
setAge(event.target.value);
};
const menuProps = {
getContentAnchorEl: null,
anchorOrigin: {
vertical: "bottom",
horizontal: "left"
},
disablePortal: true
};
return (
<StylesProvider injectFirst>
<div>
<FormControl>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={handleChange}
MenuProps={menuProps}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</div>
</StylesProvider>
);
}

Open Select after a click on label

I'm looking for a way to open a Select (not native) component from Material UI after a click on the label with htmlFor specified.
<label htmlFor='menu'>Label to open Menu</label>
<MUISelect inputProps={{id: 'menu'}} native={false}>{options}</MUISelect>
Obviously it doesn't work
There are two main aspects to this problem:
You need to get the id onto the same element that has the click-handler for opening the menu.
The element with the click-handler is a div and not an input. Labels do not automatically trigger the click event of the labelled element when it is not an input element.
The first aspect can be solved by using SelectDisplayProps:
SelectDisplayProps={{ id: "menu" }}
The second aspect can be solved with a custom label component:
import React from "react";
const LabelForClickableDiv = ({ htmlFor, ...other }) => {
const onClick = () => {
document.getElementById(htmlFor).click();
};
return <label htmlFor={htmlFor} onClick={onClick} {...other} />;
};
export default LabelForClickableDiv;
Here's a working example:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import LabelForClickableDiv from "./LabelForClickableDiv";
const useStyles = makeStyles(theme => ({
root: {
display: "flex",
flexWrap: "wrap"
},
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
function SimpleSelect() {
const classes = useStyles();
const [value, setValue] = React.useState("");
return (
<>
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl}>
<LabelForClickableDiv htmlFor="menu">
Label to open Menu
</LabelForClickableDiv>
<Select
value={value}
onChange={event => {
setValue(event.target.value);
}}
SelectDisplayProps={{
id: "menu"
}}
>
<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;

Resources