'Conditionally return ForwardRefExoticComponent and FunctionalComponent
I have created a wrapper on MUI TextField component i.e. TextFieldWrapper
with custom stylings and validations. It is being in the app in many places.
The problem with this is it cannot be used with MUI Tooltip
because for that ref
needs to be forwarded.
I cannot wrap the TextFieldWrapper
with React.forwardRef()
because wrapping it with forwardRef
will change its return type and it breaks at other places.
So, currently, I have 2 TextField
components i.e. TextFieldWrapper
and TooltipTextField
.
The issue is, as I said earlier, the TextField
has some stylings and validations applied to it and that is being duplicated in both TextFieldWrapper
and TooltipTextField
if I use separate components as shown below.
Is there a workaround for this or it could be improved in some way? I mean if I could combine these 2 (TextFieldWrapper
and TooltipTextField
) into one functional component and return it conditionally or in some way?
Code Sandbox: https://codesandbox.io/s/basictooltip-material-demo-forked-v8lrb4?file=/demo.tsx:0-799
import * as React from "react";
import { Tooltip, TextField, TextFieldProps } from "@mui/material";
// Return type is React.ForwardRefExoticComponent<Pick<TextFieldProps> & React.RefAttributes<...>>
const TooltipTextField = React.forwardRef(
(
props: TextFieldProps,
ref: React.RefObject<HTMLInputElement>
): React.ReactElement => {
return <TextField ref={ref} {...props} />;
}
);
// Return type is React.React.ReactElement
const TextFieldWrapper = (props: TextFieldProps): React.ReactElement => {
return <TextField {...props} />;
};
export default function BasicTooltip() {
return (
<>
<Tooltip title="Tooltip Textfield">
<TooltipTextField value="Tooltip TextField" />
</Tooltip>
<TextFieldWrapper value="General TextField" />
</>
);
}
Solution 1:[1]
There are three ways you can do.
- Using assertion
as
keyword and specify the type of the component you have.
const TooltipTextField = React.forwardRef(
(props: TextFieldProps, ref: React.RefObject<HTMLInputElement>) => {
return <TextField ref={ref} {...props} />;
}
) as React.FC<TextFieldProps>;
- Wrap the component with another MUI component like
Box
. This will change the target component toBox
and it will do what is needed forTooltip
.
<Tooltip title="Tooltip Textfield">
<Box sx={{ display: "inline-block" }}>
<GeneralTextField value="General TextField" />
</Box>
</Tooltip>
- Create a component combining
Tooltip
andTextField
(what you mentioned).
const TextFieldWithTooltip = ({ tooltipProps, ...rest }: TextFieldProps & { tooltipProps?: TooltipProps }): React.ReactElement => {
return (
<Tooltip {...tooltipProps} title={tooltipProps?.title || ''}>
<TextField {...rest} />
</Tooltip>
);
}
Please take a look at tooltip props at https://mui.com/material-ui/api/tooltip/#props
And notice that,
- If you pass empty string for title wont show the tooltip.
- You also can use props like
disableHoverListener
which prevents showing the tooltip, etc.
I also provided a demo on Codesandbox which may be helpful. Follow FIXME
tags in the code ;)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Adel Armand |