JSFiddle - React, Tailwind, and code Playground

HTML

<form id="myForm">
   <label for="myInput">Input:</label>
   <input type="text" id="myInput" name="myInput" data-error="Sorry, this is required!">
   <br>
   <button type="submit">Submit</button>
 </form>

CSS

.error {
  color: red;
  font-size: 14px;
  font-weight: bold;
  display: none;
  margin-top: 5px;
  border: 1px solid red;
  padding: 5px;
  border-radius: 3px;
  background-color: #fdd;
}

input.error-border {
  border: 2px solid red;
}

JavaScript

(function() {
  const CONST = {
    ERROR_ATTRIBUTE: 'data-error',
    DEFAULT_ERROR_MESSAGE: 'This is a required field',
    ERROR_BORDER_CLASS: 'error-border',
    ERROR_MESSAGE_ID: 'errorMessage',
    ERROR_MESSAGE_CLASS: 'error'
  };

  const _form = document.getElementById('myForm');
  const _input = _form ? document.getElementById('myInput') : null;

  const _init = function() {
    if (!_form) return;
    _form.addEventListener('submit', _handleSubmit);
    if (_input) {
      _input.addEventListener('input', _handleInput);
    }
  };

  const _handleSubmit = function(event) {
    if (_input.value.trim() === '') {
      event.preventDefault();
      const errorMessage = _input.getAttribute(CONST.ERROR_ATTRIBUTE) || CONST.DEFAULT_ERROR_MESSAGE;
      _input.classList.add(CONST.ERROR_BORDER_CLASS);
      _renderErrorMessage(errorMessage);
    } else {
      _input.classList.remove(CONST.ERROR_BORDER_CLASS);
      _removeErrorMessage();
    }
  };

  const _handleInput = function() {
    if (_input.value.trim() !== '') {
      _input.classList.remove(CONST.ERROR_BORDER_CLASS);
      _removeErrorMessage();
    }
  };

  const _renderErrorMessage = function(message) {
    let errorMessage = document.getElementById(CONST.ERROR_MESSAGE_ID);
    if (!errorMessage) {
      errorMessage = document.createElement('span');
      errorMessage.id = CONST.ERROR_MESSAGE_ID;
      errorMessage.className = CONST.ERROR_MESSAGE_CLASS;
      _input.insertAdjacentElement('afterend', errorMessage);
    }
    errorMessage.textContent = message;
    errorMessage.style.display = 'block';
  };

  const _removeErrorMessage = function() {
    const errorMessage = document.getElementById(CONST.ERROR_MESSAGE_ID);
    if (errorMessage) {
      errorMessage.style.display = 'none';
    }
  };

  // Initialize the module
  _init();
})();