I have a date picker that I want to show when the users click anywhere in the field not just on the calendar icon.
Here's the picker
export function DatePickerField(props) {
......
return (
<Grid container>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
{...field}
{...props}
disableToolbar
inputVariant="outlined"
value={selectedDate}
onChange={_onChange}
error={isError}
autoOk
invalidDateMessage={isError && error}
helperText={isError && error}
/>
</MuiPickersUtilsProvider>
</Grid>
);
}
I need to do this because if date entered manually, it throws no errors but I get invalid date in the form data.
How can show the picker when the field is clicked?
MUI v5 added the DatePicker component in the #mui/lab package. If you want a picker to be opened after when the user clicked inside the TextField, use MobileDatePicker, this doesn't have the calendar icon though, see this answer if you want to have one.
<MobileDatePicker
{...}
renderInput={(params) => <TextField {...params} />}
/>
The DesktopDatePicker however does have the calendar icon, but you have to write additional code to control the open state and tell the picker to open when TextField is clicked:
<DatePicker
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
renderInput={(params) => {
return (
<TextField
{...params}
onClick={(e) => setOpen(true)}
/>
);
}}
/>
Original Answer
You can control the KeyboardDatePicker's open state and set it to true when the TextField is clicked:
const [open, setOpen] = useState(false);
return (
<KeyboardDatePicker
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
TextFieldComponent={(props) => (
<TextField {...props} onClick={(e) => setOpen(true)} />
)}
{...other}
/>
);
Live Demo
Related
import React from 'react';
import {
SafeAreaView,
TextInput,
Button,
ActivityIndicator,
Text,
View,
} from 'react-native';
import {Formik} from 'formik';
import * as yup from 'yup';
import StyledInput from './styledInput';
import validationSchema from './validationSchema';
const ProductListingForm = () => (
<SafeAreaView style={{marginTop: 90}}>
<Formik
initialValues={{
listingTheme: '',
size: '',
barcode: '',
description: '',
units: '',
listingName: '',
quantity: '',
}}
onSubmit={(values, actions) => {
alert(JSON.stringify(values));
setTimeout(() => {
actions.setSubmitting(false);
}, 1000);
}}
validationSchema={validationSchema}>
{formikProps => (
<React.Fragment>
<StyledInput
label={'Product Name'}
formikProps={formikProps}
formikKey="listingName"
placeholderText={'Enter Product Name'}
autoFocus
/>
<StyledInput
label={'Product Theme'}
formikProps={formikProps}
formikKey="listingTheme"
placeholderText={'Enter a theme that describes your product'}
/>
<StyledInput
label={'Barcode'}
formikProps={formikProps}
formikKey="barcode"
placeholderText={'Scan/Enter Barcode'}
/>
<StyledInput
label={'Size'}
formikProps={formikProps}
formikKey="size"
placeholderText={'Enter Product Size'}
/>
<StyledInput
label={'Units'}
formikProps={formikProps}
formikKey="units"
placeholderText={'Enter Product Units'}
/>
<StyledInput
label={'Description'}
formikProps={formikProps}
formikKey="description"
placeholderText={'Describe your product'}
/>
{formikProps.isSubmitting ? (
<ActivityIndicator />
) : (
<Button title="Submit" onPress={formikProps.handleSubmit} />
)}
</React.Fragment>
)}
</Formik>
</SafeAreaView>
);
export default ProductListingForm;
Above is my product listing form I created using Formik. I would love to be able to add photos to this form as an array as well as saving the form data values so I can load them on a product listing card. If anyone knows how or has any guides on Formik and Firebase please help me. I just need a little guidance and then I can take it from there.
Is there a way to make it so that the <Input /> doesn't close on click? Currently, if I click inside the input, the menu just closes. I have the same setup as the original poster. I've tried playing around with closeOnSelect="false" and that didn't seem to work. Any advice would be greatly appreciated.
Here is the example in CodeSandbox form:
https://codesandbox.io/s/chakra-menuitem-as-input-forked-9ue4n
import {
Box,
Button,
ChakraProvider,
Input,
Menu,
MenuButton,
MenuItem,
MenuList,
useMenuItem,
} from '#chakra-ui/react';
import React from 'react';
const navigationKeys = ['ArrowUp', 'ArrowDown', 'Escape'];
const MenuInput = props => {
const { role, ...rest } = useMenuItem(props);
return (
<Box px="3" role={role}>
<Input
placeholder="Enter value"
size="sm"
{...rest}
onKeyDown={e => {
if (!navigationKeys.includes(e.key)) {
e.stopPropagation();
}
}}
/>
</Box>
);
};
function App() {
return (
<ChakraProvider>
<Menu>
<MenuButton as={Button}>Button</MenuButton>
<MenuList>
<MenuInput />
<MenuItem>Option 1</MenuItem>
<MenuItem>Option 2</MenuItem>
</MenuList>
</Menu>
</ChakraProvider>
);
}
export default App;
Add closeOnSelect={false} to the menu component to stop the menu closing when clicking on the MenuInput.
<Menu closeOnSelect={false}>
<MenuButton as={Button}>Button</MenuButton>
<MenuList>
<MenuInput />
<MenuItem>Option 1</MenuItem>
<MenuItem>Option 2</MenuItem>
</MenuList>
</Menu>
I am currently working on implementing the Material-UI Autocomplete component, and I want each option label to display an icon and some text. However, I only want the popper to be the full width of the text input, and then add an ellipsis to any text that would normally overflow on the Popper width.
In my renderOption method, if I return <Typography noWrap>"Text"</Typography> it succesfully forces the text to have an ellipsis, but if I put it in a Grid or Flex box in order to also include the icon, then the Popper component will be able to scroll horizontally. Is there a way to fix the Popper viewport to the width of Autocomplete, so that way the text in the renderOption method will wrap?
import React from 'react';
import InputAdornment from '#material-ui/core/InputAdornment';
import TextField from '#material-ui/core/TextField';
import SearchIcon from '#material-ui/icons/Search';
import PersonIcon from '#material-ui/icons/Person';
import GraphicEqIcon from '#material-ui/icons/GraphicEq';
import { Grid } from '#material-ui/core';
import { Autocomplete } from '#material-ui/lab';
import Typography from '#material-ui/core/Typography';
function SearchBarDisplay({ options = [], onChange, onSelectValue, value = '' }) {
function getOptionLabel(option) {
if (option.name) {
return option.name;
} else if (option.username) {
return option.username;
} else if (option.type === 'advanced') {
return option.value;
} else {
return null;
}
}
function renderOption(name, username, type) {
if (name) {
return (
<Grid container alignItems="center" spacing={1} wrap={'nowrap'}>
<GraphicEqIcon />
<Grid item>
<Typography noWrap>{name}</Typography>
</Grid>
</Grid>
);
} else if (username) {
return (
<Grid container alignItems="center" spacing={1} wrap={'nowrap'}>
<PersonIcon />
<Grid item>
<Typography noWrap>{username}</Typography>
</Grid>
</Grid>
);
} else if (type === 'advanced') {
return (
<Grid container alignItems="center" spacing={1}>
<SearchIcon />
<Grid item>
<Typography
noWrap={true}
color="textSecondary">{`See more results for "${value}"`}</Typography>
</Grid>
</Grid>
);
} else {
return null;
}
}
return (
<Autocomplete
id="autocomplete"
options={options}
getOptionSelected={(option, value) => option._id === value._id}
getOptionLabel={(option) => getOptionLabel(option)}
onChange={(event, value) => {
onSelectValue(value);
}}
onInputChange={(event, value) => onChange(value)}
renderOption={({ name, username, type }) => renderOption(name, username, type)}
renderInput={(params) => (
<TextField
{...params}
placeholder="Search for podcasts or users"
margin="normal"
variant="outlined"
InputProps={{
...params.InputProps,
startAdornment: (
<>
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
</>
)
}}
/>
)}
/>
);
}
export default SearchBarDisplay;
To change each option label to have just one line with ellipsis (... - tree dots) instead two or more lines, do you need to change your renderOption property to the follow code:
<Autocomplete
...
getOptionLabel={(option: any) => `${option.label} (${option.code})`}
renderOption={(option) => (
<React.Fragment>
<div style={{ textOverflow: 'ellipsis', overflow: "hidden", whiteSpace: "nowrap" }}>
{option.label} ({option.code})
</div>
</React.Fragment>
)}
...
/>
See an example with the countries list at CodeSandbox that I did: https://codesandbox.io/s/autocomplete-with-ellipsis-i8hnw
I have designed a form with validation using TypeScript Material UI and Formik. I want a material UI Icon to appear in my textfield area, here's my code:
import React from 'react'
import { Formik, Form, FieldAttributes,useField} from 'formik'
import { TextField } from '#material-ui/core'
import CalendarTodayIcon from '#material-ui/icons/CalendarToday'
import * as yup from 'yup'
import './MainInfo.css'
const MyTextField: React.FC<FieldAttributes<{}>> = ({
placeholder,type,className,style,
...props
}) => {
const [field, meta] = useField<{}>(props);
const errorText = meta.error && meta.touched ? meta.error : "";
return (
<div className='container'>
<TextField
placeholder={placeholder}
className={className}
style={style}
type={type}
{...field}
helperText={errorText}
error={!!errorText}
id="outlined-basic"
variant="outlined"
/>
</div>
);
};
export function MainInfo() {
return (
<div>
<Formik
validateOnChange={true} validationSchema={validationSchema} initialValues={{ Title: '', ActivationDate: '', ExpirationDate: '', DirectManager: '', HRBP: '' }} onSubmit={(data) => {
console.log(data)
}}
>
{({values, errors}) => (
<Form id='my-form' >
<div>
<label className='label'>عنوان</label>
<div >
<MyTextField style={{width:'60%'}} placeholder='طراح' name='Title' type='input' />
</div>
...
</div>
</Form>
)}
</Formik>
</div>
)
}
but the problem is that I can not add a new Icon property or InputProp since <FieldAttributes<{}>> doesnt accept it. how can I define a new property for the FieldAttributes or fix this issue?
Use the TextField Props InputProps to customize the input field
And use startAdornment, endAdornment to customize the prefix/suffix
Finally use icon inside InputAdornment would be fine
import { TextField, InputAdornment } from "#material-ui/core";
import ExpandLess from "#material-ui/icons/ExpandLess";
import ExpandMore from "#material-ui/icons/ExpandMore";
<TextField
id="standard-basic"
label="Standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<ExpandLess />
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
<ExpandMore />
</InputAdornment>
)
}}
/>
Refer:
MUI TextField Props API: InputProps, startAdornment, endAdornment
MUI InputInputAdornment Props API
online demo: https://stackblitz.com/edit/gzlbzm
I've made a custom User Confirmation Dialog from Material UI Dialog component like here
I faced a problem to overwrite the Dialog's font. I can overwrite color or background color, but fonts in Dialog's header or buttons are inherited from Material-UI. I successfully overwrote Material-UI fonts in other components, but not in this part with callback:
const UserConfirmation = (
message: string,
callback: (shouldNavigate: boolean) => void
) => {
const container = document.createElement('div')
container.setAttribute('custom-confirmation-navigation', '')
document.body.appendChild(container)
const closeModal = (shouldNavigate: boolean) => {
ReactDOM.unmountComponentAtNode(container)
callback(shouldNavigate)
}
ReactDOM.render(
<>
<Dialog
fullWidth={true}
maxWidth="sm"
open={true}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitleWrapper
style={{fontFamily: `BuenosAires !important`, color: `orange`}}
>
Discard draft?
</DialogTitleWrapper>
<DialogContent>
<p> {message} </p>
</DialogContent>
<DialogActionsWrapper>
<Button
onClick={() => closeModal(true)}
fullWidth={true}
variant="outlined"
label="Discard"
/>
<div style={{ width: '80%' }} />
<Button
onClick={() => closeModal(false)}
fullWidth={true}
variant="contained"
label="Cancel"
/>
</DialogActionsWrapper>
</Dialog>
</>,
container
)
}
export default UserConfirmation
Thank Alex
That works brilliant for me:
<DialogTitle disableTypography="true">
Also, buttons' labels were fixed by that:
label={<h5 style={{ textTransform: 'none' }}>Cancel</h5>}
You can use classes object to Override or extend the styles applied to the component.
here
create custom styles like below
const useStyles = makeStyles({
customDialogTitle: {
fontFamily:'Impact'//sans-serif
}
});
and assign to classes
<DialogTitle disableTypography="true"
classes={{
root: classes.customDialogTitle
}}
>
.....
</DialogTitle>
sample sandbox