react password eye icon for multiple fields

Viewed 23142

I have three password fields, each one has a eye icon to let consumer show/hide password,

I am trying with the below code but if i click hide/show for one field then it is effecting to other fields too.

Please guide me with any example of correct the below code

class ShowPassword extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      type: 'input',
      score: 'null'
    }
    this.showHide = this.showHide.bind(this);
  }

  showHide(e){
    //e.preventDefault();
    //e.stopPropagation();
    this.setState({
      type: this.state.type === 'input' ? 'password' : 'input'
    })  
  }


  render(){
    return(
      <div>
      <label className="password">Current Password
      <input type={this.state.type} className="password__input"/>
      <span className="password__show" onClick={this.showHide}>{this.state.type === 'input' ? 'Hide' : 'Show'}</span>
      </label>

            <label className="password">New Password
      <input type={this.state.type} className="password__input"/>
      <span className="password__show" onClick={this.showHide}>{this.state.type === 'input' ? 'Hide' : 'Show'}</span>
      </label>

            <label className="password">Confirm Password
      <input type={this.state.type} className="password__input"/>
      <span className="password__show" onClick={this.showHide}>{this.state.type === 'input' ? 'Hide' : 'Show'}</span>
      </label>
        </div>
    )
  }
}

ReactDOM.render(<ShowPassword/>, document.getElementById('react'));

Below is the jsbin link to play with

https://jsbin.com/homuxoq/edit?html,css,js,output

3 Answers

Extract your input field into it's own component

class PasswordField extends React.Component{
  state = {
    type: 'text',
  }


  handleClick = () => this.setState(({type}) => ({
    type: type === 'text' ? 'password' : 'text'
  }))


  render() {
    const { label } = this.props

    return (
      <label className="password">{label}
        <input type={this.state.type} className="password__input"/>
        <span className="password__show" onClick={this.handleClick}>{this.state.type === 'text' ? 'Hide' : 'Show'}</span>
      </label>
    )
  }
}

Link to JSBin

Another thing I'd like to mention here, is that there is no input type of input. Therefore I've replaced it with the valid value text.

when you are setting state all of inputs get rendered by new type value that you provide to this.state.type

you should remove type={this.state.type} for input that you don't want to take effect by show/hide button simply use type="password"

Each of your password field should have their own state containing a boolean staing if they are hidden or shown. To avoid code repetitions, make a Component for your passwords.

Working example :

class ShowPassword extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            score: 'null'
        }
    }

    render() {
        return (
            <div>
                <PasswordField title='Current Password'/>
                <PasswordField title='New Password' />
                <PasswordField title='Confirm Password' />
            </div>
        )
    }
}

class PasswordField extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            hide: true
        }
    }

    hideSwitch = ev => {
        this.setState({ hide: !this.state.hide })
    }

    render() {
        const { title } = this.props
        const { hide } = this.state
        return (
            <label className="password">{title}
                <input type={hide ? 'password' : 'input'} className="password__input" />
                <span className="password__show" onClick={this.hideSwitch}>{hide ? 'Show' : 'Hide'}</span>
            </label>
        )
    }
}

ReactDOM.render(<ShowPassword/>, document.getElementById('react'));
$accent: #00BCD4;
$primary: #212121;
$secondary: #727272;

$scoreRed: #F44336;
$scoreYellow: #FFEB3B;
$scoreGreen: #4CAF50;

body, html{
  height: 100%;
}

body{
  background: linear-gradient(#607D8B, #455A64);
  font-family: 'Roboto', sans-serif;
}

form{
  margin: 3em auto;
  max-width: 320px;
  background: #FFFFFF;
  padding: 40px;
  box-shadow: 0 0 20px rgba(0,0,0,.25);
  
}
.password{
  display: block;
  position: relative;
  text-transform: uppercase;
  font-weight: 700;
  width: 100%;
  color: $secondary;
  
  &__input{
    display: block;
    text-transform: none;
    width: 100%;
    height: 42px;
    border-width: 0 0 1px;
    border-style: solid;
    border-color: #B6B6B6;
    font-weight: 400;
    color: $primary;
    
    &:focus, &:active{
      border-color: $accent;
      outline: 0;
    }
  }
  
  &__show{
    cursor: pointer;
    position: absolute;
    bottom: 11px;
    height: 16px;
    right: 0;
    background: $secondary;
    color: white;
    padding: 4px 8px;
    border-radius: 4px;
    font-weight: 700;
    font-size: .8em;
  }
  
  &__strength{
    position: absolute;
    width: 0%;
    height: 4px;
    bottom: -8px;
    left: 0;
    background: transparent;
    transition: all 300ms ease-in-out;
    
    &[data-score="null"]{
      width: 0;
      background: red;
    }
    
    &[data-score="0"]{
      width: 5%;
      background: $scoreRed;
    }
    &[data-score="1"]{
      width: 25%;
      background: $scoreRed;
    }
    &[data-score="2"]{
      width: 50%;
      background: $scoreYellow;
    }
    &[data-score="3"]{
      width: 75%;
      background: $scoreGreen;
    }
    &[data-score="4"]{
      width: 100%;
      background: $scoreGreen;
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.0/umd/react-dom.production.min.js"></script>
<form id="react"></form>

Related