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);