Reputation: 1097
I am trying to implement custom input element for TextField component from Material UI
example :
export const InputsPage: React.FC = () => {
const [value, setValue] = useState('');
return (
<Paper>
<Box p={2}>
<TextField
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
color='primary'
label='FROM'
placeholder='Placeholder'
InputProps={{
inputComponent: ({ inputRef, ...rest }) => <input ref={inputRef} {...rest} type='text' />,
}}
/>
</Box>
</Paper>
);
};
because i am using controlled input with my own state the input is not working properly ... each time ill trying to type some thing the input will loss focus so i need to type each char/number and make a click on the input again to make a focus so i can continue typing
if ill use uncontrolled input it will work properly
here is an example what is happening : codeSandbox
Upvotes: 5
Views: 16765
Reputation: 192
If you want to use masked input with material ui and form library you could do this:
import React, { memo } from "react";
// MASKED INPUT
import MaskedInput from "react-text-mask";
// MATERIAL UI
import { Phone } from "@mui/icons-material";
import { InputAdornment, TextField } from "@mui/material";
interface MaskedPhoneInputProps {
fieldRef: (ref: HTMLElement | null) => void;
field: any;
errors: any;
}
const MaskedPhoneInput = ({
fieldRef,
field,
errors,
}: MaskedPhoneInputProps) => {
return (
<MaskedInput
{...field}
ref={(ref) => {
fieldRef(ref ? ref.inputElement : null);
}}
mask={[
"0",
"(",
/[1-9]/,
/\d/,
/\d/,
")",
" ",
/\d/,
/\d/,
/\d/,
"-",
/\d/,
/\d/,
/\d/,
/\d/,
]}
guide={false}
keepCharPositions
render={(ref, props) => (
<TextField
inputRef={ref}
{...props}
variant="outlined"
label="Telefon Numarası"
fullWidth
size="small"
placeholder="Telefon numaranızı giriniz"
error={!!errors?.phone}
helperText={errors?.phone?.message}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Phone sx={{ color: "text.disabled" }} />
</InputAdornment>
),
}}
/>
)}
/>
);
};
export default memo(MaskedPhoneInput);
Then you could use it in any controller (formik, react hook form) like this:
<Controller
name="phone"
control={control}
rules={{ required: true }}
render={({ field: { ref, ...rest } }) => (
<MaskedPhoneInput fieldRef={ref} field={rest} errors={errors} />
)}
/>
WARNING
ref={(ref) => {
fieldRef(ref ? ref.inputElement : null);
}}
Defining ref like it is important, if you don't define you may take error about focus like elm.focus is not a function in react hook form.
Upvotes: 0
Reputation: 80986
The problem is that you are defining inline the component type for the inputComponent
prop. This means that with each re-render it will be considered by React to be a new component type, so instead of just re-rendering, the element will be remounted (removed completely from the DOM and re-added) which results in focus being lost.
You can fix this by defining the component type (CustomInputComponent
in the example) at the top-level as shown in the example below:
import React, { useState } from "react";
import "./styles.css";
import { TextField } from "@material-ui/core";
const CustomInputComponent = ({ inputRef, ...rest }) => (
<input ref={inputRef} {...rest} type="text" />
);
export default function App() {
const [value, setValue] = useState("");
return (
<div className="App">
<TextField
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
color="primary"
label="FROM"
placeholder="Placeholder"
InputProps={{
inputComponent: CustomInputComponent
}}
/>
</div>
);
}
Upvotes: 7