JSFiddle - React, Tailwind, and code Playground

by Davi Amorim

HTML

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col-12">

      <div class="table-responsive">
        <table class="table table-fixed">
          <thead>
            <tr>
              <th>Coluna 1</th>
              <th>Coluna 2</th>
              <!-- Largura fixa para evitar quebras -->
              <th width="222px">Dimensões (cm)</th>
              <th>Coluna 4</th>
              <th>Coluna 5</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><input type="text" class="form-control"></td>
              <td><input type="text" class="form-control"></td>
              <td class="triple-input">
                <!-- step indica que o campo vai aumentar 0.1 cm de cada vez -->
                <!-- min indica o mínimo que o campo aceita. Se for um número negativo, ficará inválido -->
                <input type="number" step="0.1" min="0" placeholder="C" class="form-control">
                <div class="error">Apenas números, por favor.</div>
                <input type="number" step="0.1" min="0" placeholder="L" class="form-control">
                <div class="error">Apenas números, por favor.</div>
                <input type="number" step="0.1" min="0" placeholder="A" class="form-control">
                <div class="error">Apenas números, por favor.</div>
              </td>
              <td><input type="text" class="form-control"></td>
              <td><input type="text" class="form-control"></td>
          ...

CSS

/* Talvez isso esteja faltando no CSS... */

.table-fixed {
  table-layout: fixed;
}

.triple-input .form-control {
  width: 50px;
  display: inline-block;
  margin-right: 10px;
}

.triple-input .form-control:last-child {
  margin-right: 0px;
  /* O último input não precisa do margin-right */
}

.error {
  position: absolute;
  font-size: 85%;
  color: white;
  background: tomato;
  padding: 0 10px;
  border-radius: 10px;
  transform: translateY(9px);
  opacity: 0;
  visibility: hidden;
  transition: all 200ms ease-in-out;
}
.error:before {
  content: '';
  display: block;
  position: absolute;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 7px solid tomato;
  top: -7px;
}

/* O pseudo-seletor :invalid serve para indicar quando o campo está inválido */

/* No caso, ele adiciona uma borda vermelha quando o campo está errado (quando tem um número negativo) */

.triple-input .form-control:invalid {
  border-color: tomato;
  box-shadow: 0 0 0 0.2rem rgba(255, 99, 71, 0)
}

.triple-input .form-control:invalid + .error {
  opacity: 1;
  visibility: visible;
}

.triple-input .form-control:focus:invalid {
  box-shadow: 0 0 0 0.2rem rgba(255, 99, 71, .25);
}

/* deixa o input type=number com aparência igual a um type=text */

input[type=number] {
  -webkit-appearance: textfield;
  -moz-appearance: textfield;
}

input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

JavaScript

console.clear();

(function($) {

	$(document).on('click', '.remove', function() {
  	if( $('tbody tr').length == 1 ) {
    	return false;
    }
    // $(this).parents('tr')  procura a tr (linha) a qual o botão está inserido
  	$(this).parents('tr').remove();
  });
  
  $(document).on('click', '.add', function() {
  // 1. $(this).parents('tr')  procura a tr (linha) a qual o botão está inserido
  // 2. Clona a linha
  // 3. Insere na tabela
  	var new_tr = $(this).parents('tr').clone(true);
    $(new_tr).appendTo('tbody');
  });

})(jQuery);