JSFiddle - React, Tailwind, and code Playground

by Abdul Ahmad

HTML

<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

SCSS

body {
  font-family: sans-serif;
  color: #444444;
  margin: 0;
  background: #cfd3d6;
}

input {
  outline: none;
  box-sizing: border-box;
  padding: 20px 15px;
  border-radius: 3px;
  border: 1px solid #ddd;
  font-size: 16px;
}

button {
  border: none;
  padding: 15px 20px;
  border-radius: 5px;
  box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.3);
  outline: none;
  background: white;
  font-size: 16px;
}

.app {
}

.form-box {
  position: fixed;
  top: 20px;
  opacity: 1;
  left: calc(50% - 150px);
  padding: 40px;
  border-radius: 3px;
  box-sizing: border-box;
  width: 300px;
  background: white;
  margin: 20px;
  box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.3);
  transition: top 0.3s ease, opacity 0.3s ease;
  
  &.hidden {
    top: -100px;
    opacity: 0;
    transition: top 0.3s ease, opacity 0.3s ease;
  }
}

.form-input-box {
  margin-top: 30px;
  
  &:first-of-type {
    margin-top: 0;
  }
}

.form-input-label {
  display: block;
  font-size: 16px;
  font-weight: bold;
}

.form-input {
  margin-top: 8px;
  width: 100%;
}

.form-input-message {
  font-size: 14px;
  margin-top: 3px;
  
  &.error {
    color: #e8186b;
  }
  
  &.success {
    color: #24c384;
  }
}

.submit-button-box {
  margin-top: 30px;
  text-align: center;
}

.submit-button {
  @extend button;
  background: #24c384;
  color: white;
  box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.3);
  
  &:active {
    background: darken(#24c384, 15%);
  }
}

Babel + JSX

class App extends React.Component {
  render() {
    return <div className='app'>
      <Form />
    </div>;
  }
}

class Form extends React.Component {
	constructor(props) {
  	super(props);
    
    this.state = {
    	formClass: 'hidden',
      nameInput: {
        name: 'name',
        label: 'Name',
        value: '',
        message: '',
        messageClass: '',
      },
      emailInput: {
        name: 'email',
        label: 'Email',
        value: '',
        message: '',
        messageClass: '',
      },
      messageInput: {
        name: 'message',
        label: 'Message',
        value: '',
        message: '',
        messageClass: '',
      },
    };
    
    setTimeout(() => { this.setState({ formClass: '' }); }, 1000);
    
    this.submit = this.submit.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
  }
  
  submit() {
  	let inputsAreValid = true;
    const { nameInput, emailInput, messageInput } = this.state;
    const inputs = [nameInput, emailInput, messageInput];
  	inputs.forEach((input) => {
    	if (!input.value) {
        this.setState({ 
        	[input.name + 'Input']: {
          	...input,
          	message: 'This field is required',
            messageClass: 'error',
          } 
        });
      	inputsAreValid = false;
      }
    });
    
    if (!inputsAreValid) return;
    this.setState({ formClass: 'hidden' });
  }
  
  onInputChange(e) {
  	const { name, value } = e.target;
  	const input = this.state[name + 'Input'];
  	this.setState({
    	[name + 'Input']: {
      	...input,
        value: value,
        message: '',
        messageClass: '',
      }
    });
  }
  
	render() {
  	const { nameInput, emailInput, messageInput, formClass } = this.state;
    
  	return (
      <div className={`form-box ${formClass}`}>
        <FormInput 
          label={nameInput.label}
          value={nameInput.value}
          onChange={this.onInputChange} 
          name={nameInput.name}
         ...