<main></main>
.panel {
  border:1px solid gray;
  width:80px;
  height:80px;
  margin: 10px;
  display:inline-block;
  vertical-align:top;
  font-size: 30px;
  line-height:80px;
  text-align:center;
}

.panel:focus {
  background: #c8c8c8;
}
class CustomInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { focus: 0, value: [' ', ' ', ' ', ' '] };
  }
  
  componentDidUpdate() {
    const focus = this.state.focus;    
    this.el.querySelectorAll('.panel')[focus].focus();
  }
  
  setCharacter(i, e) {
    const newVal = [...this.state.value];
    newVal[i] = String.fromCharCode(e.charCode);
    
    this.setState({
      value: newVal,
      focus: (this.state.focus + 1) % this.state.value.length,
    })
  }
  
  render() {
    const chars = this.state.value;
    
    return <div ref={(el) => { this.el = el }}>
      {chars.map((c, i) => (
        <div 
          onFocus={(e) => this.setState({ focus: i })}
          onKeyPress={(e) => this.setCharacter(i, e)}
          tabIndex={1} 
          key={i} 
          className="panel">{c}</div>
      ))}      
    </div>
  }  
}

ReactDOM.render(<CustomInput />, document.querySelector('main'));
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://fb.me/react-15.1.0.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js
  3. https://fb.me/react-dom-15.1.0.min.js