'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
askeyword 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 toBoxand 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
TooltipandTextField(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
disableHoverListenerwhich 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 |
