Author: | fivefifteen |
---|---|
Views Total: | 0 views |
Official Page: | Go to website |
Last Update: | April 17, 2025 |
License: | MIT |
Preview:

Description:
Kloner is a lightweight and customizable JavaScript library that allows you to duplicate/repeat elements (element group) with no dependencies.
It can be useful when working with form fields that need to be duplicated, such as multiple address inputs, contact information entries, or any repeatable blocks of content.
Features:
- Easy Setup: Just requires adding specific data attributes to your HTML.
- Automatic Indexing: Handles updating
{kloner-index}
and{kloner-number}
placeholders in cloned elements, crucial for form field names and IDs. - Configurable: Options available via JavaScript initialization or
data-kloner-*
attributes. - Lifecycle Callbacks: Provides hooks like
beforeAdd
,afterAdd
,beforeRemove
,afterRemove
for custom logic. - Min/Max Limits: Control the minimum and maximum number of cloned items.
See it in action:
How to use it:
1. Install and import Kloner with NPM.
# NPM $ npm install kloner
// ES6 import kloner from 'kloner' // CommonJS const kloner = require('kloner')
2. Or load the kloner.min.js script in the document.
<script src="kloner.min.js"></script>
3. Initialize Kloner once the DOM is ready.
window.addEventListener('load', function () { kloner() })
4. To create a cloneable element, you need a container element, a template element inside it (the one to be cloned), and add/remove trigger buttons.
- The container (
div#people
) uses thekloner
class. Kloner will automatically find it. data-kloner-child-selector=".person"
tells Kloner which element inside the container is the template. If omitted, it tries[data-kloner-template]
or the first direct child.- Placeholders like
{kloner-index}
and{kloner-number}
inside the template (.person
) are automatically replaced with the correct zero-based index and one-based number when cloned. This is essential for form fieldname
andid
attributes. - Buttons with
data-kloner-add
anddata-kloner-remove
attributes handle the cloning and removal actions. The remove button typically sits inside the cloned element.
<div id="people" class="container people-grid kloner" data-kloner-child-selector=".person"> <div class="person"> <p>Person #{kloner-number}</p> <fieldset> <label for="people[{kloner-index}][first_name]">First Name</label> <input type="text" id="people[{kloner-index}][first_name]" name="people[{kloner-index}][first_name]" /> </fieldset> <fieldset> <label for="people[{kloner-index}][last_name]">Last Name</label> <input type="text" id="people[{kloner-index}][last_name]" name="people[{kloner-index}][last_name]" /> </fieldset> <fieldset> <label for="people[{kloner-index}][age]">Age</label> <input type="number" id="people[{kloner-index}][age]" name="people[{kloner-index}][age]" min="1" max="99" /> </fieldset> <button type="button" class="btn btn-custom" data-kloner-remove>Remove Person</button> </div> <div class="btn-container"> <button type="button" class="btn btn-custom" data-kloner-add>Add Person</button> </div> </div>
5. Configure Kloner during initialization or via data-kloner-*
attributes on the container element.
containerSelector: '[data-kloner], .kloner'
- CSS selector used to find the main container elements that Kloner should manage.
childSelector: '[data-kloner-template], :scope > *'
- CSS selector used within each container to identify the template element that will be cloned.
:scope
refers to the container itself.
- CSS selector used within each container to identify the template element that will be cloned.
min: 0
- The minimum number of cloned items that must remain. Kloner prevents removal below this count.
max: null
- The maximum number of cloned items allowed. Kloner prevents adding more items beyond this limit.
null
means no limit.
- The maximum number of cloned items allowed. Kloner prevents adding more items beyond this limit.
start: 0
- Specifies the initial number of items to create when Kloner initializes. Can be an integer for empty clones or an array of parameter objects to populate initial clones with specific data.
template: null
- Allows providing an HTML string directly as the template, bypassing the need for a template element within the container specified by
childSelector
.
- Allows providing an HTML string directly as the template, bypassing the need for a template element within the container specified by
updateChildren: false
- If set to
true
, Kloner will re-evaluate and update the{kloner-index}
and{kloner-number}
placeholders in all existing child elements after any add or remove operation. Can impact performance with many items.
- If set to
parameters: null
- An object containing custom key-value pairs. These are used to replace corresponding
{kloner-yourKey}
placeholders within the template HTML.
- An object containing custom key-value pairs. These are used to replace corresponding
beforeAdd: null
- A callback function executed just before a new element is added to the DOM. Receives
(container, newElement, options)
. Returningfalse
cancels the add operation.
- A callback function executed just before a new element is added to the DOM. Receives
afterAdd: null
- A callback function executed immediately after a new element has been added to the DOM. Receives
(container, newElement, options)
. Useful for initializing third-party scripts on the new element.
- A callback function executed immediately after a new element has been added to the DOM. Receives
beforeRemove: null
- A callback function executed just before an element is removed. Receives
(container, elementToRemove, options)
. Returningfalse
cancels the remove operation.
- A callback function executed just before an element is removed. Receives
afterRemove: null
- A callback function executed immediately after an element has been removed from the DOM. Receives
(container, removedElement, options)
.
- A callback function executed immediately after an element has been removed from the DOM. Receives
beforeChildUpdate: null
- A callback function executed before updating placeholders on an existing child element, only relevant if
updateChildren
istrue
. Receives(container, element, options)
. Returningfalse
skips the update for this specific element.
- A callback function executed before updating placeholders on an existing child element, only relevant if
afterChildUpdate: null
- A callback function executed after updating placeholders on an existing child element, only relevant if
updateChildren
istrue
. Receives(container, element, options)
.
- A callback function executed after updating placeholders on an existing child element, only relevant if
kloner({ afterAdd: null, afterChildUpdate: null, afterRemove: null, beforeAdd: null, beforeChildUpdate: null, beforeRemove: null, childSelector: '[data-kloner-template], :scope > *', containerSelector: '[data-kloner], .kloner', max: null, min: 0, parameters: null, start: 0, template: null, updateChildren: false })
6. API methods.
// Adds a new element at the specified index kloner.add(container, [index], [options]) // Removes an element at the specified index kloner.remove(container, [index], [options]) // Gets Kloner instances matching the selector kloner.getInstances(selector, [verify], [single]) // Updates indices and numbers for all children kloner.updateChildren(container) // Replaces placeholders with actual values kloner.replaceParameters(element, parameters)
FAQs
Q: How do I handle event listeners on cloned elements? My date picker / select library doesn’t work.
A: Standard cloneNode(true)
doesn’t copy event listeners attached via addEventListener
. You need to initialize any JS components or attach listeners after the element is cloned and added to the DOM. The afterAdd
callback is the perfect place for this. Pass the newElement
argument from the callback to your initialization function (e.g., new DatePicker(newElement.querySelector('.datepicker'))
).
Q: How can I pass initial data or different values into each cloned item?
A: Use the start
option during initialization. If you provide an array of objects to start
, Kloner will call add
for each object, passing the object as parameters
. You can then use custom placeholders like {kloner-firstName}
in your template, and Kloner will replace them with values from the corresponding object in the start
array. Example: start: [{firstName: 'John'}, {firstName: 'Jane'}]
. You can also call container.kloner.add(null, { parameters: { yourKey: 'yourValue' } })
programmatically.
Q: What if my template element needs to be hidden initially?
A: You can hide the template element using CSS (e.g., display: none;
). Kloner clones it from memory, so its initial visibility state doesn’t prevent cloning. Alternatively, mark it with data-kloner-template
. Kloner automatically removes elements matching [data-kloner-template]
after identifying them during initialization.
Q: Is it possible to reset a Kloner container back to its initial state?
A: There isn’t a built-in reset()
method. You’d typically remove all cloned items programmatically by repeatedly calling container.kloner.remove()
until the minimum count is reached, or manually remove the elements via DOM manipulation and then potentially re-initialize Kloner on the container if needed.