11

I am trying to create a custom button component in a React Typescript project that use React Hooks and Styled components.

// Button.tsx
import React, { MouseEvent } from "react";
import styled from "styled-components";

export interface IButtonProps {
    children?: React.ReactNode;
    props?: any;
    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
        | undefined;
}

const Button: React.FC<IButtonProps> = ({
    children,
    onClick = () => {},
    ...props
}) => {
    const handleOnClick = (e: MouseEvent<HTMLButtonElement>) => {
        onClick(e);
    };
    return (
        <ButtonStyles onClick={handleOnClick} {...props}>
            {children}
        </ButtonStyles>
    );
};

export default Button;

const ButtonStyles = styled.button``;

This is the component I want to use my custom Button

// Login.tsx
import React from "react";
import Button from "../../components/Generic/Button/Button";

const Login: React.FC = () => {
    const clickMe = () => {
        console.log("Button Clicks");
    };

    return (
        <div>
            <Button onClick={clickMe}>My Button</Button>
        </div>
    );
};

export default Login;

I want to click on my custom button and want to print the console log message when I click on it. But I am getting the following error. How to resolve this issue?

Argument of type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to parameter of type 'MouseEvent<HTMLButtonElement, MouseEvent<Element, MouseEvent>>'.
  Type 'MouseEvent' is missing the following properties from type 'MouseEvent<Element, MouseEvent>': nativeEvent, isDefaultPrevented, isPropagationStopped, persist  TS2345

    16 | }) => {
    17 |    const handleOnClick = (e: MouseEvent<HTMLButtonElement>) => {
  > 18 |        onClick(e);
       |                ^
    19 |    };
    20 |    return (
    21 |        <ButtonStyles onClick={handleOnClick} {...props}>
4
  • I believe your clickMe method is missing the event argument. Try chaning it to clickMe(e). Commented Feb 27, 2020 at 15:12
  • @kaveh I think you mean this: <Button onClick={e => clickMe(e)}>My Button</Button> , but still getting the error. Commented Feb 27, 2020 at 15:15
  • No, I mean where you actually create clickMe, so const clickMe = () => {...} should be const clickMe = (e) => {...} Commented Feb 27, 2020 at 15:35
  • nope, it didn't work as well. Commented Feb 27, 2020 at 15:44

6 Answers 6

21

UPDATED:

if you want to include them aria props enter image description here

new


import React from "react";

export interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, React.AriaAttributes  {}

export const ButtonPrimary:React.FC<ButtonProps> = props => {
    const {children, ...rest} = props;

    return (
        <button {...rest}>{children}</button>
    )
}

old

import * as React from "react";


export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}


/**
 * Button.
 *
 * @param {ButtonProps} props button's props
 * @returns {React.ReactElement<ButtonProps>} Button.
 */
export function Button(props: ButtonProps): React.ReactElement<ButtonProps> {
    const { children, ...rest } = props;
    return (
        <button
            {...rest}
        >
            {children}
        </button>
    );
}
Sign up to request clarification or add additional context in comments.

1 Comment

The useful part for me was interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
7

Your interface IButtonProps defines the expected signature of onClick

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
        | undefined;

However, the e argument to handleClick is defined differently as MouseEvent<HTMLButtonElement>

If you change the onClick signature to match your handleClick definition, that may go some way to fix it?

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement>) => void)
        | undefined;

Comments

3
// Button.tsx
import React from "react";
import styled from "styled-components";

interface IButtonProps {
    children?: React.ReactNode;
    props?: any;
    onClick?: any;
}

const MyButton: React.FC<IButtonProps> = ({ onClick, children, ...props }) => {
    return (
        <ButtonStyles {...props} onClick={onClick}>
            {children}
        </ButtonStyles>
    );
};

export default MyButton;

const ButtonStyles = styled.button``;

// Login.tsx
import React from "react";
import MyButton from "../../components/Generic/Button/Button";

const Login: React.FC = () => {
    const ClickMe = () => {
        console.log("Button Clicked");
    };

    return (
        <div>
            <MyButton onClick={ClickMe}>Hello MY Button</MyButton>
        </div>
    );
};

export default Login;

I just able to fix the issue by changing the type of onClick?: any This is not the best solution, but at least it didn't throw any error and I can perform the onClick action in my Login.tsx.

Comments

0

The code snippet should work fine.

export interface ButtonProps
    extends React.ButtonHTMLAttributes<HTMLButtonElement> {
    // customProps
  }

const Button: React.FC<ButtonProps> = ({ children }) => {
    return <button>{children}</button>;
};

export default Button;

Comments

0

You could try this one:

import type { ButtonHTMLAttributes, FC } from "react";

interface IProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  checked: boolean;
  onChange: () => void;
};

const SwitchButton: FC<IProps> = ({ checked, onChange, ...props }) => {
  return (
    <button
      className={`relative w-10 h-5 rounded-full flex items-center px-0.5 transition-colors duration-300 ease-in-out focus:outline-none ${
        checked ? "bg-primary" : "bg-grey-light"
      }`}
      onClick={onChange}
      role="switch"
      aria-checked={checked}
      {...props}>
      <span
        className={`block w-4 h-4 rounded-full bg-white transform transition-transform duration-300 ease-in-out ${
          checked ? "translate-x-5" : ""
        }`}
      />
    </button>
  );
};

export default SwitchButton;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Please explain what you've changed to address the issue. Code-only answers are not good answers
0

You could also use ComponentProps and use with any HTML element, in this case a button:

// Button.tsx

import React from 'react';

interface ButtonProps extends React.ComponentProps<'button'> {
  children: React.ReactNode;
}

function Button({ children }: ButtonProps): React.ReactElement {
  return <button>{children}</button>;
}

export default Button;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.