I just can\'t wrap my head around this I guess, I\'ve tried probably half a dozen times and always resort to any
... Is there a legitimate way to start with an HTML
Seems Like the above answer is outdated.
In my case I'm wrapping a styled component with a functional component, but still want to expose regular HTML button properties.
export const Button: React.FC<ButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>> = ({ children, icon, ...props}) => (
<StyledButton { ...props}>
{ icon && (<i className = "material-icons" >{icon}< /i>)}
{children}
</StyledButton>);
I solve this code for me, you just have to import ButtonHTMLAttributes
from react and that's it
import { ButtonHTMLAttributes } from "react";
interface MyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: any;
}
export const MyButton = (props: ButtonI) => {
const { children } = props;
return <button {...props}>{children}</button>;
};
You can change the definition of your component to allow the react html button props
class MyButton extends React.Component<MyButtonProps & React.HTMLProps<HTMLButtonElement>, {}> {
render() {
return <button {...this.props}/>;
}
}
That will tell the typescript compiler that you want to enter the button props along with 'MyButtonProps'
I encountered the same issue today and here is how I fixed it:
ReactButtonProps.ts
import {
ButtonHTMLAttributes,
DetailedHTMLProps,
} from 'react';
/**
* React HTML "Button" element properties.
* Meant to be a helper when using custom buttons that should inherit native "<button>" properties.
*
* @example type MyButtonProps = {
* transparent?: boolean;
* } & ReactButtonProps;
*/
export type ReactButtonProps = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;
Usage in Button-ish
component:
import classnames from 'classnames';
import React, { ReactNode } from 'react';
import { ReactButtonProps } from '../../types/react/ReactButtonProps';
type Props = {
children: ReactNode;
className?: string;
mode?: BtnMode;
transparent?: boolean;
} & ReactButtonProps;
const BtnCTA: React.FunctionComponent<Props> = (props: Props): JSX.Element => {
const { children, className, mode = 'primary' as BtnMode, transparent, ...rest } = props;
// Custom stuff with props
return (
<button
{...rest} // This forward all given props (e.g: onClick)
className={classnames('btn-cta', className)}
>
{children}
</button>
);
};
export default BtnCTA;
Usage:
<BtnCTA className={'test'} onClick={() => console.log('click')}>
<FontAwesomeIcon icon="arrow-right" />
{modChatbot?.homeButtonLabel}
</BtnCTA>
I can now use onClick
because it's allowed due to extending from ReactButtonProps, and it's automatically forwarded to the DOM through the ...rest
.
I always like to do it this way:
import React from 'react';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
title: string;
showIcon: boolean;
}
const Button: React.FC<ButtonProps> = ({ title, showIcon, ...props }) => {
return (
<button {...props}>
{title}
{showIcon && <Icon/>}
</button>
);
};
Then you can do:
<Button
title="Click me"
onClick={() => {}} {/* You have access to the <button/> props */}
/>
private yourMethod(event: React.MouseEvent<HTMLButtonElement>): void {
event.currentTarget.disabled = true;
}
<Button
onClick={(event) => this.yourMethod(event)}
/>