JSFiddle - React, Tailwind, and code Playground

by Nahuel Scotti

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.12/vue.min.js"></script>
<div id="app">
  <h1>Valid: {{ result.valid }} / Type: {{ result.type }}</h1>
  <input v-model="dni" :class="{'valid': result.valid}">
</div>

CSS

#app { padding: 30px }
* {
  box-sizing: border-box;
  font-family: "Roboto", "Helvetica";
  font-weight: 300;
  font-size: 18px;
}

input {
  color: red;
  background-color: lightpink;
  outline: none;
  border: 1px solid grey;
  padding: 5px 10px;
  font-size: 32px;
  width: 250px;
}

input.valid {
  color: green;
  background-color: lightgreen;
}

JavaScript

function validate(value) {
  var validChars = 'TRWAGMYFPDXBNJZSQVHLCKET';
  var nifRexp = /^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/i;
  var nieRexp = /^[XYZ]{1}[0-9]{7}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/i;
  var str = value.toString().toUpperCase();

  var isNIF = nifRexp.test(str);
  var isNIE = nieRexp.test(str);
  if (!isNIF && !isNIE) return {
    valid: false,
    type: ''
  };

  var nie = str
    .replace(/^[X]/, '0')
    .replace(/^[Y]/, '1')
    .replace(/^[Z]/, '2');

  var letter = str.substr(-1);
  var charIndex = parseInt(nie.substr(0, 8)) % 23;

  if (validChars.charAt(charIndex) === letter) {
    return {
      valid: true,
      type: (isNIF ? 'NIF' : (isNIE ? 'NIE' : ''))
    }
  }

  return {
    valid: false,
    type: ''
  };
}

new Vue({
  el: '#app',
  data: {
    dni: '12345678Z'
  },
  computed: {
    result: function() {
      return validate(this.dni);
    }
  }
});