Hi,
looks like whatever I try the button-has-type rule can't understand the default prop.
type Props = {
type: 'submit' | 'button' | 'reset',
};
function Button({ type, ...extraProps }: Props) {
return <button type={type} {...extraProps} />;
}
Button.defaultProps = {
type: 'submit',
};
````
error "null" is an invalid value for button type attribute react/button-has-type
```jsx
type Props = {
type: 'submit' | 'button' | 'reset',
};
function Button({ type = 'submit', ...extraProps }: Props) {
return <button type={type} {...extraProps} />;
}
````
error "null" is an invalid value for button type attribute react/button-has-type
```
How are you creating the <Button> element? Note that null doesn’t trigger defaults, but undefined does.
Oh, i see that this is the linter reporting it. This seems like a bug.
I'm getting the same error.
It seems that the button type attribute cannot be dynamic. But I don't understand why...
It is required to be static for a number of reasons; one is that it’s lintable, but also because each kind of button is a fundemantally different component/element - they’re not just different “flavors” of button.
@ljharb In our component library at my company we have a Button component that is used for various things. We use a oneOf prop type to do an enum of type options and default to button since that's the sane default. But the button can be used technically as a submit or reset button (and does get used).
We have a component due to css and classes, its easier to have one shared one where the app people don't have to worry about css classes and semantics, they can just use our Button.
I don't want to turn this rule off, but if its going to be forced to be static, don't really see another way.
@truckingsim what i'd expect is that you'd have that Button component wrapped by SubmitButton and ResetButton components, and inside those you'd override the rule for the dynamic type - but you wouldn't need that anywhere else.
(ofc, this is separate from the issue that reset buttons are terrible UX and shouldn't ever be on the page)
@ljharb that's what I just did, but also feels like I shouldn't have to do that.
Is there no way to take props into consideration for rules? So that basically if there's a default + it only allows what is expected it passes?
If you can come up with a way for the rule to assert that the prop has a propType (or flow/TS type) that only permits one of the proper values, and that that prop is the dynamic value passed in, then that absolutely seems like something that could be allowed.
I'm not sure how to implement that, but I'd be happy to review a PR that achieves that.
Is it acceptable for the rule to just bail out when type is a curly expression?
Not by default; the intention is for the rule to forced a hardcoded inline string type.

It's like taking the variable name as a string value.
@JeromeLin https://github.com/yannickcr/eslint-plugin-react/issues/1846#issuecomment-401849676 ; we should make that error message better but it’d still need to be static.
eeeee
iam getting the same error. 好烦!
A coworker of mine just hit this same issue. She figured out two ways around the issue.
While all of the following feels hacky, these options might help until this bug is fixed.
Option 1: Store your button type in a variable named for one of the valid button types.
function Button({ type, ...extraProps }: Props) {
const button = type;
return <button type={button} {...extraProps} />;
}
Option 2: Disable this linter rule just for this line of code:
function Button({ type, ...extraProps }: Props) {
// eslint-disable-next-line react/button-has-type
return <button type={type} {...extraProps} >;
}
Happy coding!
@peoplespete note that Option 1 working is actually a bug, which will be fixed very soon :-) Option 2 is the proper workaround.
Most helpful comment
@ljharb In our component library at my company we have a Button component that is used for various things. We use a
oneOfprop type to do an enum of type options and default to button since that's the sane default. But the button can be used technically as a submit or reset button (and does get used).We have a component due to css and classes, its easier to have one shared one where the app people don't have to worry about css classes and semantics, they can just use our Button.
I don't want to turn this rule off, but if its going to be forced to be static, don't really see another way.