JSFiddle - React, Tailwind, and code Playground

by Viruthagiri

HTML

<body>
  <h2>Click + or - to Clone</h2>
  <br/>
  <div class='project_group'>
    <input id='user_project_name' name='user[project][name]'></input>
    <input id='user_project_description' name='user[project][description]'></input>
    <input type="file" id='user_project_image' name='user[project][image]'></input>
  </div>
  <br/>
</body>

CSS

.simple_wrapper {
  display: block;
}
.simple_wrapper .simple_label {
  float: left;
  margin-right: 20px;
}
.simple_wrapper .simple_plus, .simple_wrapper .simple_minus {
  float: left;
  cursor: pointer;
  padding: 0 0.5em;
}
.simple_wrapper .left {
  float: left;
}
.simple_wrapper .simple_clear {
  clear: both;
}

JavaScript

$(document).ready(function(){
      $(".project_group").simple_clone({
        nested: true
});
});

(function($) {

$.fn.simple_clone = function(option){
  var option = option || {};

  var e = $(this);
  e.addClass("left")
  var out_wrapper = "<div class='outer_simple_wrapper'></div>"
  var wrapper = "<div class='simple_wrapper'></div>"
  var plus = "<span class='simple_plus'>+</span>"
  var minus = "<span class='simple_minus'>-</span>"
  var clear = "<div class='simple_clear'></div>";

  // ------------  case 1: if have already multiple groups
  if(e.length > 1) {
    e.wrap(wrapper);
    // we only wrapper one outer_simple_wrapper for all groups
    var existing_outer_wrapper;
    e.each(function(i){
      existing_outer_wrapper = $(this).parent().siblings(".outer_simple_wrapper");
      if(existing_outer_wrapper.length == 0) {
        $(this).parent().wrap(out_wrapper);
      } else {
        $(this).parent().appendTo(existing_outer_wrapper);
      }
      // append '- +' after the last group, otherwise append only a '-'
      if(i == e.length-1){
        $(this).after(plus).after(minus);
      } else{
        $(this).after(minus);
      }
    })
  }
  // ------------- case 2: if only has one wrapper, general case
  else{
    // wrap wrappers
    e.wrap(out_wrapper).wrap(wrapper);
    // if the list can be empty (all elements can be removed), add an "-" after the first elements
    if(option.canBeEmpty) {
      e.after(minus);
    }
    // add an original "+" after the elements
    e.after(plus);
  }

  // append a initial number to elements id, if options[:nested] true, also assign a initial number to the element name
  e.find("input, select").each(function(){
    var old_id = $(this).attr("id");
    $(this).attr("id", old_id+'_0');
    if(option.nested == true) {
      var old_name = $(this).attr("name");
      var reg = /\[\w*\]$/;
      var match = reg.exec(old_name);
      var new_name = old_name.substr(0, match.index) + "[0]" + match[0];
     ...