126

I want to dynamically include/omit the disabled attribute on a button element. I have seen plenty of examples of dynamic attribute values, but not of attributes themselves. I have the following render function:

render: function() {
    var maybeDisabled = AppStore.cartIsEmpty() ? "disabled" : "";
    return <button {maybeDisabled}>Clear cart</button>
}

This throws a parse error because of the "{" character. How can I include/omit the disabled attribute based on the (boolean) result of AppStore.cartIsEmpty()?

Timmy
  • 1,262
  • 2
  • 8
  • 8

11 Answers11

196

The cleanest way to add optional attributes (including disabled and others you might want to use) is currently to use JSX spread attributes:

var Hello = React.createClass({
    render: function() {
        var opts = {};
        if (this.props.disabled) {
            opts['disabled'] = 'disabled';
        }
        return <button {...opts}>Hello {this.props.name}</button>;
    }
});

React.render((<div><Hello name="Disabled" disabled='true' />
    <Hello name="Enabled"  />
</div>)
, document.getElementById('container'));

By using spread attributes, you can dynamically add (or override) whatever attributes you'd like by using a javascript object instance. In my example above, the code creates a disabled key (with a disabled value in this case) when the disabled property is passed to the Hello component instance.

If you only want to use disabled though, this answer works well.

Community
  • 1
  • 1
WiredPrairie
  • 58,954
  • 17
  • 116
  • 143
  • Once in place, CSS like: `a[disabled] { pointer-events: none; }` will stop actions on an element/component – timbo Jan 02 '18 at 22:51
68

I'm using React 16 and this works for me (where bool is your test):

<fieldset {...(bool && {disabled:true})}>

Basically, based on the test (bool) you return an object with the conditional attributes or you don't.

Also, if you need to add or omit multiple attributes you can do this:

<fieldset {...(bool && {disabled:true, something:'123'})}>

For more elaborate attribute managed I suggest you prefab the object with (or without) the attributes outside of JSX.

Community
  • 1
  • 1
Luke
  • 20,878
  • 35
  • 119
  • 178
56

You can pass a boolean to the disabled attribute.

render: function() {
    return <button disabled={AppStore.cartIsEmpty()}>Clear cart</button>
}

function Test() {
  return (
    <div>
      <button disabled={false}>Clear cart</button>
      <button disabled={true}>Clear cart</button>
    </div>
  );
}

ReactDOM.render(<Test />, document.querySelector("#test-container"));
console.log(Array.from(document.querySelectorAll("button")));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="test-container"></div>
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
Alexandre Kirszenberg
  • 35,938
  • 10
  • 88
  • 72
  • 11
    no you cannot. the presence of the disabled attribute disables the button completely. see [http://jsfiddle.net/ttjhyvmt/](http://jsfiddle.net/ttjhyvmt/) – Timmy Mar 17 '15 at 15:46
  • 22
    React is clever enough to conditionally set the `disabled` attribute on the resulting HTML depending on the value you passed http://jsfiddle.net/kb3gN/10379/ – Alexandre Kirszenberg Mar 17 '15 at 15:50
  • 2
    not sure how I missed that, thank you! whilst this works for my specific case, I have accepted another answer which omits/includes attributes – Timmy Mar 17 '15 at 15:55
  • 1
    Had issues with IE11, however, we were not using the latest react. The JSX spread attributes answer worked. – LessQuesar Jun 28 '16 at 20:39
6

Far cleaner than the accepted solution is the solution which AnilRedshift mentioned, but which I'll expand on.

Simply put, HTML attributes have a name and a value. As a shorthand, you can use the name only for "disabled", "multiple", etc. But the longhand version still works, and allows for React to work in it's preferred way.

disabled={disabled ? 'disabled' : undefined} is the most legible solution.

jhchnc
  • 439
  • 6
  • 17
6

A simple and clean way of doing it

<button {...disabled && {disabled: true}}>Clear cart</button>

disabled should come from props like this

<MyComponent disabled />
Yogiyo
  • 61
  • 1
  • 3
5

The version I used was:

<button disabled={disabled ? 'disabled' : undefined}>
    Click me (or dont)
</button>
AnilRedshift
  • 7,937
  • 7
  • 35
  • 59
  • 1
    It is a bad practice to use undefined in your code. It is also unnecessary as you could simply write – Raphael Pinel Dec 10 '19 at 12:35
  • Why is undefined bad practice? Citation if possible. Also perhaps react properly handles bools now but at nhe time of writing your suggestion would not work correctly – AnilRedshift May 19 '20 at 06:02
4

More cleaner way of doing dynamic attributes which works for any attributes is

function dynamicAttributes(attribute, value){
  var opts = {};
  if(typeof value !== 'undefined' && value !== null) {
    opts['"'+attribute+'"'] = value;
    return opts;
  }
  return false;
};

Call in your react component like following

<ReactComponent {...dynamicAttributes("disabled",false)}
{...dynamicAttributes("data-url",dataURL)}
{...dynamicAttributes("data-modal",true)} />

Tips :

  1. You could have dynamicAttributes function in a common place/utilities and import it to use it across all components

  2. you could pass value as null to not render dynamic attribute

Venkat Reddy
  • 1,046
  • 1
  • 8
  • 13
  • Why not do like this: ? it simpler and no "dynamicAttributes" needed – gdbdable Nov 23 '18 at 13:54
  • In case of attribute is null, we don't want react to render that attribute. example: "data-modal": null we don't want react to show data-model="null". in this case my above code wont even show attribute i.e, dynamic attribute based on value. – Venkat Reddy Dec 18 '18 at 01:35
2

You can find something similar to this at the documentation.

https://facebook.github.io/react/docs/transferring-props.html

In your case could be something like this

function MyComponent(props) {
    let { disabled, ...attrs } = props;
    if (disabled) {
        // thus, it will has the disabled attribute only if it
        // is disabled
        attrs = {
            ...attrs,
            disabled: true
        }
    };

    return (
        <button {...attrs}>MyLabel</button>
    )
}

This code is using ES6, but I thing you got the idea.

This is cool because you can pass many others attributes to this component and it will still work.

1

In case others come here for attributes other than disabled, e.g., custom attributes like data-attr, one can assign empty string "" as the value in the object to be spread to eliminate the value of the attribute. With the attribute name only available on the resulted HTML.

For example:

<div {...(trueOrFalse && { [`data-attr`]: "" })}></div>

Furthermore, if you wish the name of the attribute being dynamic too. Due to template strings support string interpolation, you can put state into it to make the name of attribute dynamic.

<div {...(trueOrFalse && { [`${state}`]: "" })}></div>
krave
  • 1,629
  • 4
  • 17
  • 36
0

First you can simply check

<button disabled={true}>Button 1</button>
<button disabled={false}>Button 2</button>

Note: **disabled value is not String, it should be Boolean.

Now for dynamic. You can simply write

<button type="button" disabled={disable}  
        onClick={()=>this.setSelectValue('sms')} >{this.state.sms}</button>

As you can see I am using disabled property and in curly brackets it can be local variable/state var. The variable disable contains values true/false.

m02ph3u5
  • 3,022
  • 7
  • 38
  • 51
-3

This could work, problem with disabled is one could not simply set boolean for it.

if(AppStore.cartIsEmpty()){
  return "<button disabled>Clear cart</button>"
}
else
{
  return "<button>Clear cart</button>"
}
IcyBright
  • 654
  • 4
  • 15
  • I was afraid I might have to resort to this.. I'll wait to see if anybody else has any suggestions before accepting your answer – Timmy Mar 17 '15 at 15:40