I am making a custom input component with MUI InputBase, and I want to have a "Clear" button endAdornment that only appears when you hover over the input:
<InputBase
inputComponent={getCustomInputComponent()}
onClick={onClick}
...
endAdornment={
<IconButton
size='small'
onClick={handleClear}>
<IconClear fontSize='small'/>
</IconButton>
}
/>
Similar to how their new "Autocomplete" component works: https://material-ui.com/components/autocomplete/
I've looked at the source code of Autocomplete but I can't get it working in my component, any suggestions?
Below is an example that is roughly equivalent to what is being done in Autocomplete. The gist of the approach is to make the icon hidden by default, then flip the visibility to visible on hover of the input (&:hover $clearIndicatorDirty) and when the input is focused (& .Mui-focused), but only if there is currently text in the input (clearIndicatorDirty is only applied when value.length > 0).
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import IconButton from "#material-ui/core/IconButton";
import ClearIcon from "#material-ui/icons/Clear";
import clsx from "clsx";
const useStyles = makeStyles(theme => ({
root: {
"&:hover $clearIndicatorDirty, & .Mui-focused $clearIndicatorDirty": {
visibility: "visible"
}
},
clearIndicatorDirty: {},
clearIndicator: {
visibility: "hidden"
}
}));
export default function CustomizedInputBase() {
const classes = useStyles();
const [value, setValue] = React.useState("");
return (
<TextField
variant="outlined"
className={classes.root}
value={value}
onChange={e => setValue(e.target.value)}
InputProps={{
endAdornment: (
<IconButton
className={clsx(classes.clearIndicator, {
[classes.clearIndicatorDirty]: value.length > 0
})}
size="small"
onClick={() => {
setValue("");
}}
>
<ClearIcon fontSize="small" />
</IconButton>
)
}}
/>
);
}
Related documentation:
https://cssinjs.org/jss-plugin-nested?v=v10.0.0#use-rulename-to-reference-a-local-rule-within-the-same-style-sheet
Related
I am having a problem with radio button selection.
handleChange event is triggering but dot does not appear on selection.
The count of objects is happening , checked in console.log.
I need to render a radio button list , I am using map method to iterate through the values.
Community appreciate your help !
import * as React from 'react';
import {Box, FormControl, FormControlLabel, RadioGroup, Radio } from '#mui/material'
function RadioBtnItem(props) {
const {
id,
name
} = props;
const [position, setPosition] = React.useState('id');
const handleChange = event => {
console.warn(event.target.value)
setPosition(event.target.value)
};
return (
<Box>
<FormControl component='fieldset'
>
<RadioGroup
name='positions-group'
arial-labelledby='positions-group-label'
onChange={handleChange}
value={id}
>
<FormControlLabel
value={id}
control={<Radio />}
label={name}
checked={position === {id}}
key={id} />
</RadioGroup>
</FormControl>
</Box>
);
}
export { RadioBtnItem };
I'm using the Autocomplete component as in the country example, but decorated with the InputAdornment component in order to show the flag of the select country.
Here the working code:
The problem: after picking a country, if the user clicks exactly on the flag, country's name is selected. And, if the user clicks on the remaining part of the Autocomplete, the Popper is showing up (as expected and that's totally ok).
Current behaviour:
MY GOAL: I'd like to open the Autocomplete Popper even when clicking on the flag.
Expected behaviour:
I tried to use the option disablePointerEvents in the InputAdornment parameters, but nothing changed.
I tried the same on a pure Textfield MUI component and it worked, so it maybe it is something related to Autocomplete only.
Is there a workaround for this issue?
Same issue here
One solution is to control the open state of the Autocomplete using the open, onOpen, and onClose props and then add an onClick (instead of disablePointerEvents) to the InputAdornment to open the Autocomplete.
Here is a working example based on your sandbox:
import * as React from "react";
import Box from "#mui/material/Box";
import TextField from "#mui/material/TextField";
import Autocomplete from "#mui/material/Autocomplete";
import InputAdornment from "#mui/material/InputAdornment";
export default function CountrySelect() {
const [value, setValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
return (
<Autocomplete
id="country-select-demo"
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
sx={{ width: 300 }}
options={countries}
autoHighlight
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
getOptionLabel={(option) => option.label}
renderOption={(props, option) => (
<Box
component="li"
sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
{...props}
>
<img
loading="lazy"
width="20"
src={`https://flagcdn.com/w20/${option.code.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${option.code.toLowerCase()}.png 2x`}
alt=""
/>
{option.label} ({option.code}) +{option.phone}
</Box>
)}
renderInput={(params) => (
<TextField
{...params}
label="Choose a country"
inputProps={{
...params.inputProps,
autoComplete: "new-password" // disable autocomplete and autofill
}}
InputProps={{
...params.InputProps,
startAdornment: value ? (
<InputAdornment position="start" onClick={() => setOpen(true)}>
<img
loading="lazy"
width="48"
src={`https://flagcdn.com/w20/${value.code.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${value.code.toLowerCase()}.png 2x`}
alt=""
/>
</InputAdornment>
) : null
}}
/>
)}
/>
);
}
I wanted to customize the datepicker and tried to remove the padding from the input in the mui-x datepicker but nothing was working.
Am i doing something wrong here or is styled not supported by mui-x?
import { styled } from '#mui/material/styles';
import { DesktopDatePicker, LocalizationProvider } from '#mui/x-date-pickers';
import { DatePicker } from '#mui/x-date-pickers/DatePicker';
import { AdapterDateFns } from '#mui/x-date-pickers/AdapterDateFns';
import { TextField } from '#mui/material';
const DateDisplay = styled(DesktopDatePicker)(({ theme }) => ({
'& input':{
padding: 0,
},
}));
return (
<ModalDialog>
<div>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateDisplay
value={new Date()}
readOnly
onChange={() => {}}
renderInput={(params) => <TextField {...params} />}
></DateDisplay>
</LocalizationProvider>
</div>
</ModalDialog>
);
};
Use sx={{}} prop.
<DateDisplay
value={new Date()}
readOnly
onChange={() => {}}
renderInput={(params) => (
<TextField
{...params}
sx={{
'.MuiInputBase-input': {padding: 0},
}}
/>
)}
></DateDisplay>
With '.MuiInputBase-input' class, you can customize your <TextField> render input for your DatePicker.(You can also see it in the picture)
I have a subscription dialog form. I want the email field to be required, but I am currently able to submit my form with a blank email address (which would be a major problem for the client!). I have it marked as required in my code, but that doesn't seem to be translating to my UI.
I am using Material UI for styling.
Any pointers are sincerely appreciated :)
In the picture, see how I was able to click subscribe with no email address (the submit message appears after clicking subscribe).
import React from 'react';
import Button from '#material-ui/core/Button';
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import Grid from '#material-ui/core/Grid';
import { Typography } from '#material-ui/core';
import { Form } from 'react-final-form';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
padding: theme.spacing(2)
},
divider: {
marginBottom: theme.spacing(2)
}
}));
export default function SubscribeFormResults() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [formSubmitted, setFormSubmitted] = React.useState(false);
const onSubmit = async values => {
console.log('Submitting subscribe form!');
console.log('Subscribe form values:', values);
setFormSubmitted(true);
};
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
setFormSubmitted(false);
};
const validate = values => {
const errors = {};
if (!values.userEmail) {
errors.userEmail = 'Required';
}
return errors;
};
return (
<div>
<Button size="small" color="primary" onClick={handleClickOpen}>
Subscribe
</Button>
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Subscribe</DialogTitle>
<DialogContent>
<Form
onSubmit={onSubmit}
initialValues={{ userEmail: 'johndoe#example.com', arn: 'Connect to Backend!' }}
validate={validate}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} noValidate>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates
occasionally.
</DialogContentText>
<TextField
label="Email Address"
name="userEmail"
margin="none"
required={true}
fullWidth
/>
{formSubmitted && <Grid item xs={12}>
<Typography name='submitMessage' variant='subtitle1'>You have subscribed to AA-01-23-45-678901-2. {/* Connect to backend here */}</Typography>
</Grid>}
<DialogActions>
<Button /* onClick={handleClose} */ color="primary" type="submit" disabled={submitting}>
Subscribe
</Button>
<Button onClick={handleClose} color="primary">
Close
</Button>
</DialogActions>
</form>
)}
/>
</DialogContent>
</Dialog>
</div>
);
}
For future readers, I fixed this by removing the validation parameter from the Material UI, uppercase Form tag and enforced validation using the standard, lowercase form tag.
Using TextField as the input param of Select gives the following warning:
Material-UI: children must be passed when using the TextField component with select.
<Select
multiple
value="value"
fullWidth
input={
<TextField name="name" id="id" variant="outlined" label="test"/>
}
>
<MenuItem>1</MenuItem>
<MenuItem>2</MenuItem>
</Select>
What is the proper implementation of the same?
The proper way is to render a TextField as parent component, and providing it select prop
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import MenuItem from '#material-ui/core/MenuItem';
import TextField from '#material-ui/core/TextField';
const useStyles = makeStyles(theme => ({
root: {
width: '100px'
},
}));
export default function SelectTextField() {
const classes = useStyles();
return (
<TextField
classes={{root:classes.root}}
select
name="name"
id="id"
variant="outlined"
label="test"
SelectProps={{
multiple: true,
value: []
}}
>
<MenuItem>1</MenuItem>
<MenuItem>2</MenuItem>
</TextField>
);
}
Code Sandbox