How to extend and add props to a Theme UI component (with TypeScript) #1895
-
I'd like to create a I'd like this new import React, { ReactNode } from 'react'
import {
Box,
ThemeUIStyleObject,
Button as ThemeUIButton,
ButtonProps as ThemeUIButtonProps,
} from 'theme-ui'
import { Loader } from '../Loader'
// ForwardRef was copied from Theme UI's own types because it is not exported
type ForwardRef<T, P> = React.ForwardRefExoticComponent<
React.PropsWithoutRef<P> & React.RefAttributes<T>
>
export interface ButtonProps
extends ForwardRef<HTMLButtonElement, ThemeUIButtonProps> {
isLoading?: boolean
sx?: ThemeUIStyleObject
children: ReactNode
}
export const Button = ({
sx,
isLoading,
children,
...rest
}: ButtonProps): JSX.Element => {
return (
<ThemeUIButton
sx={{
position: 'relative',
display: 'inline-flex',
alignItems: 'center',
...sx,
}}
{...rest}
disabled={isLoading}
>
<Box
as="span"
sx={{
visibility: isLoading ? 'hidden' : 'visible',
}}
>
{children}
</Box>
{isLoading && (
<Loader
size="1.5em"
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
color: 'bright',
}}
/>
)}
</ThemeUIButton>
)
} This code actually works but TypeScript doesn't like it when I use the FYI, I have seen #1071 which does not help here. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
In order for your component to continue to support ref forwarding like the Theme UI button does, while still having your component be functional as opposed to class based, you'll have to actually call the As far as your props interface goes, the component itself should be typed as a You also shouldn't need to explicitly add Putting all that together it should look something like export interface ButtonProps extends ThemeUIButtonProps {
isLoading?: boolean;
}
const Button: ForwardRef<HTMLButtonElement, ButtonProps> = forwardRef(
(props, ref) => {
const { isLoading, ...themeUiButtonProps } = props
return (
// extra stuff, use the isLoading prop, you get the idea
<ThemeUIButton ref={ref} {...themeUiButtonProps} />
)
}
); |
Beta Was this translation helpful? Give feedback.
@mrmartineau
In order for your component to continue to support ref forwarding like the Theme UI button does, while still having your component be functional as opposed to class based, you'll have to actually call the
React.forwardRef()
function (see https://reactjs.org/docs/forwarding-refs.html)As far as your props interface goes, the component itself should be typed as a
ForwardRef
instance, not the props signature. The props themselves can just extend the aliasedThemeUIButtonProps
.You also shouldn't need to explicitly add
sx
orchildren
to your interface if you're extendingThemeUIButtonProps
Putting all that together it should look something like