186

I'm trying to disable a button when an input field is empty. What is the best approach in React for this?

I'm doing something like the following:

<input ref="email"/>

<button disabled={!this.refs.email}>Let me in</button>

Is this correct?

It's not just duplication of the dynamic attribute, because I'm also curious about transferring/checking the data from one element to another.

starball
  • 20,030
  • 7
  • 43
  • 238
Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176
  • 3
    possible duplicate of [Dynamic attribute in ReactJS](http://stackoverflow.com/questions/29103096/dynamic-attribute-in-reactjs) – WiredPrairie May 12 '15 at 10:34

6 Answers6

281

You'll need to keep the current value of the input in state (or pass changes in its value up to a parent via a callback function, or sideways, or <your app's state management solution here> such that it eventually gets passed back into your component as a prop) so you can derive the disabled prop for the button.

Example using state:

<meta charset="UTF-8">
<script src="https://fb.me/react-0.13.3.js"></script>
<script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
<div id="app"></div>
<script type="text/jsx;harmony=true">void function() { "use strict";

var App = React.createClass({
  getInitialState() {
    return {email: ''}
  },
  handleChange(e) {
    this.setState({email: e.target.value})
  },
  render() {
    return <div>
      <input name="email" value={this.state.email} onChange={this.handleChange}/>
      <button type="button" disabled={!this.state.email}>Button</button>
    </div>
  }
})

React.render(<App/>, document.getElementById('app'))

}()</script>
Jonny Buchanan
  • 61,926
  • 17
  • 143
  • 150
  • @STEVER This is because in Angular you have the notion of 2-way bindings, while React "forces" 1-way binding. There is special mixin you can use to simulate a 2-way binding for these simple cases of linking child value props to a field in the state: LinkedStateMixin – Nico Jun 19 '15 at 14:30
  • 5
    Awesome, the example runs and everything. Nice complete example and nice interactive demo, SO. – four43 Nov 23 '15 at 16:43
  • 2
    This wont work because `disabled`, by merely being attached to an element, means that the element is to be disabled. Its not a bool. See this: https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/disabled – Kayote Jul 11 '18 at 14:27
  • 7
    @Kayote that is not true for React. Those tags are not HTML, they're JSX. And in JSX, if an attribute is assigned false, it is removed entirely when converting to HTML. Did you just ignore the comment immediately above yours that says that it runs perfectly? – Ben Baron Aug 21 '18 at 03:15
  • 2
    @BenBaron thanks for the clarification. I do not remember where / how I used it, however, I had a few issues. Im upvoting your comment so others know that this method is the correct method based on people's experience. – Kayote Aug 22 '18 at 10:45
  • 3
    @Kayote Thanks and sorry if I came off a bit rude with the last part of the comment. It was a really long day. – Ben Baron Aug 24 '18 at 03:06
  • @BenBaron yes its work in simple situation but does not work in TextField material-ui. Any idea how to make it work ? – Yasir Mar 06 '19 at 14:39
  • @YasirAkbar sorry I've never used the material-ui package, so i have no idea how it works. – Ben Baron Mar 07 '19 at 00:03
  • How do we access this in CSS to change the way the button looks though? `.button:disabled` doesn't seem to work... – Zap Sep 12 '19 at 18:13
11

Using constants allows to combine multiple fields for verification:

class LoginFrm extends React.Component {
  constructor() {
    super();
    this.state = {
      email: '',
      password: '',
    };
  }
  
  handleEmailChange = (evt) => {
    this.setState({ email: evt.target.value });
  }
  
  handlePasswordChange = (evt) => {
    this.setState({ password: evt.target.value });
  }
  
  handleSubmit = () => {
    const { email, password } = this.state;
    alert(`Welcome ${email} password: ${password}`);
  }
  
  render() {
    const { email, password } = this.state;
    const enabled =
          email.length > 0 &&
          password.length > 0;
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="Email"
          value={this.state.email}
          onChange={this.handleEmailChange}
        />
        
        <input
          type="password"
          placeholder="Password"
          value={this.state.password}
          onChange={this.handlePasswordChange}
        />
        <button disabled={!enabled}>Login</button>
      </form>
    )
  }
}

ReactDOM.render(<LoginFrm />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<body>


</body>
Gi1ber7
  • 632
  • 1
  • 11
  • 22
9

Another way to check is to inline the function, so that the condition will be checked on every render (every props and state change)

const isDisabled = () => 
  // condition check

This works:

<button
  type="button"
  disabled={this.isDisabled()}
>
  Let Me In
</button>

but this will not work:

<button
   type="button"
   disabled={this.isDisabled}
>
  Let Me In
</button>
Marc Sloth Eastman
  • 693
  • 1
  • 10
  • 19
2
const Example = () => {
  
const [value, setValue] = React.useState("");

function handleChange(e) {
    setValue(e.target.value);
  }

return (


<input ref="email" value={value} onChange={handleChange}/>
<button disabled={!value}>Let me in</button> 

);

}
 
export default Example;
  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – blazej Aug 02 '21 at 15:12
0
<button disabled={false}>button WORKS</button>
<button disabled={true}>button DOES NOT work</button>

Now just use useState or any other condition to pass true/false into the button, assuming you are using React.

fruitloaf
  • 1,628
  • 15
  • 10
-2

its simple let us assume you have made an state full class by extending Component which contains following

class DisableButton extends Components 
   {

      constructor()
       {
         super();
         // now set the initial state of button enable and disable to be false
          this.state = {isEnable: false }
       }

  // this function checks the length and make button to be enable by updating the state
     handleButtonEnable(event)
       {
         const value = this.target.value;
         if(value.length > 0 )
        {
          // set the state of isEnable to be true to make the button to be enable
          this.setState({isEnable : true})
        }


       }

      // in render you having button and input 
     render() 
       {
          return (
             <div>
                <input
                   placeholder={"ANY_PLACEHOLDER"}
                   onChange={this.handleChangePassword}

                  />

               <button 
               onClick ={this.someFunction}
               disabled = {this.state.isEnable} 
              /> 

             <div/>
            )

       }

   }
keerthi c
  • 51
  • 7