How to disable button in React.js

JavascriptReactjs

Javascript Problem Overview


I have this component:

import React from 'react';

export default class AddItem extends React.Component {

add() {
    this.props.onButtonClick(this.input.value);
    this.input.value = '';
}


render() {
    return (
        <div className="add-item">
            <input type="text" className="add-item__input" ref={(input) => this.input = input} placeholder={this.props.placeholder} />
            <button disabled={!this.input.value} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
        </div>
    );
}

}

I want the button to be disabled when input value is empty. But the code above doesn't work. It says:

>add-item.component.js:78 Uncaught TypeError: Cannot read property 'value' of undefined

pointing to disabled={!this.input.value}. What can I be doing wrong here? I'm guessing that perhaps ref isn't created yet when render method is executed. If, so what is the workararound?

Javascript Solutions


Solution 1 - Javascript

Using refs is not best practice because it reads the DOM directly, it's better to use React's state instead. Also, your button doesn't change because the component is not re-rendered and stays in its initial state.

You can use setState together with an onChange event listener to render the component again every time the input field changes:

// Input field listens to change, updates React's state and re-renders the component.
<input onChange={e => this.setState({ value: e.target.value })} value={this.state.value} />

// Button is disabled when input state is empty.
<button disabled={!this.state.value} />

Here's a working example:

class AddItem extends React.Component {
  constructor() {
    super();
    this.state = { value: '' };
    this.onChange = this.onChange.bind(this);
    this.add = this.add.bind(this);
  }

  add() {
    this.props.onButtonClick(this.state.value);
    this.setState({ value: '' });
  }

  onChange(e) {
    this.setState({ value: e.target.value });
  }

  render() {
    return (
      <div className="add-item">
        <input
          type="text"
          className="add-item__input"
          value={this.state.value}
          onChange={this.onChange}
          placeholder={this.props.placeholder}
        />
        <button
          disabled={!this.state.value}
          className="add-item__button"
          onClick={this.add}
        >
          Add
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <AddItem placeholder="Value" onButtonClick={v => console.log(v)} />,
  document.getElementById('View')
);

<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>
<div id='View'></div>

Solution 2 - Javascript

In HTML,

<button disabled/>
<buttton disabled="true">
<buttton disabled="false">
<buttton disabled="21">

All of them boils down to disabled="true" that is because it returns true for a non-empty string. Hence, in order to return false, pass a empty string in a conditional statement like this.input.value?"true":"".

render() {
    return (
        <div className="add-item">
            <input type="text" className="add-item__input" ref={(input) => this.input = input} placeholder={this.props.placeholder} />
            <button disabled={this.input.value?"true":""} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
        </div>
    );
}

Solution 3 - Javascript

Here is a functional component variety using react hooks.

The example code I provided should be generic enough for modification with the specific use-case or for anyone searching "How to disable a button in React" who landed here.

import React, { useState } from "react";

const YourComponent = () => {
  const [isDisabled, setDisabled] = useState(false);
  
  const handleSubmit = () => {
    console.log('Your button was clicked and is now disabled');
    setDisabled(true);
  }

  return (
      <button type="button" onClick={handleSubmit} disabled={isDisabled}>
        Submit
      </button>
  );
}

export default YourComponent;

Solution 4 - Javascript

You shouldn't be setting the value of the input through refs.

Take a look at the documentation for controlled form components here - https://facebook.github.io/react/docs/forms.html#controlled-components

In a nutshell

<input value={this.state.value} onChange={(e) => this.setState({value: e.target.value})} />

Then you will be able to control the disabled state by using disabled={!this.state.value}

Solution 5 - Javascript

There are few typical methods how we control components render in React. enter image description here

But, I haven't used any of these in here, I just used the ref's to namespace underlying children to the component.

class AddItem extends React.Component {
    change(e) {
      if ("" != e.target.value) {
        this.button.disabled = false;
      } else {
        this.button.disabled = true;
      }
    }

    add(e) {
      console.log(this.input.value);
      this.input.value = '';
      this.button.disabled = true;
    }

    render() {
        return (
          <div className="add-item">
          <input type="text" className = "add-item__input" ref = {(input) => this.input=input} onChange = {this.change.bind(this)} />
          
          <button className="add-item__button" 
          onClick= {this.add.bind(this)} 
          ref={(button) => this.button=button}>Add
          </button>
          </div>
        );
    }
}

ReactDOM.render(<AddItem / > , document.getElementById('root'));

<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>
<div id="root"></div>

Solution 6 - Javascript

very simple solution for this is by using useRef hook

const buttonRef = useRef();

const disableButton = () =>{
  buttonRef.current.disabled = true; // this disables the button
 }

<button
className="btn btn-primary mt-2"
ref={buttonRef}
onClick={disableButton}
>
	Add
</button>

Similarly you can enable the button by using buttonRef.current.disabled = false

Solution 7 - Javascript

this.input is undefined until the ref callback is called. Try setting this.input to some initial value in your constructor.

From the React docs on refs, emphasis mine:

> the callback will be executed immediately after the component is mounted or unmounted

Solution 8 - Javascript

I have had a similar problem, turns out we don't need hooks to do these, we can make an conditional render and it will still work fine.

<Button
	type="submit"
	disabled={
		name === "" || email === "" || password === "" ? true : false
	}
	fullWidth
	variant="contained"
	color="primary"
	className={classes.submit}>
	SignUP
</Button>

Solution 9 - Javascript

just Add:

<button disabled={this.input.value?"true":""} className="add-item__button" onClick={this.add.bind(this)}>Add</button>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondKabView Question on Stackoverflow
Solution 1 - JavascriptFabian SchultzView Answer on Stackoverflow
Solution 2 - JavascriptVarnika ChaturvediView Answer on Stackoverflow
Solution 3 - JavascriptNanoCatView Answer on Stackoverflow
Solution 4 - JavascriptT MitchellView Answer on Stackoverflow
Solution 5 - JavascriptprostiView Answer on Stackoverflow
Solution 6 - JavascriptNabeel Hussain ShahView Answer on Stackoverflow
Solution 7 - JavascriptdamdView Answer on Stackoverflow
Solution 8 - JavascriptAgnibha ChatterjeeView Answer on Stackoverflow
Solution 9 - Javascriptnh DalimView Answer on Stackoverflow