116

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,162
  • 2
  • 7
  • 8

10 Answers10

189

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
  • 57,121
  • 16
  • 110
  • 141
  • Once in place, CSS like: `a[disabled] { pointer-events: none; }` will stop actions on an element/component – timbo Jan 02 '18 at 22:51
53

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
  • 16,643
  • 2
  • 22
  • 46
Alexandre Kirszenberg
  • 34,953
  • 9
  • 86
  • 72
  • 9
    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
  • 21
    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
47

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
  • 19,965
  • 32
  • 112
  • 171
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
  • 429
  • 5
  • 17
5

The version I used was:

<button disabled={disabled ? 'disabled' : undefined}>
    Click me (or dont)
</button>
AnilRedshift
  • 7,306
  • 7
  • 33
  • 57
  • 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,063
  • 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
4

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
  • 41
  • 3
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.

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
  • 2,837
  • 6
  • 38
  • 49
-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
  • 14
  • 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