Examples
Basic Usage
Click "Add item" to clone the input block into the container. A limit of 3 is set so the trigger disables after three clones.
< div class = "max-w-xs w-full" >
< div id = "repeater-wrapper-basic" class = "space-y-3" >
< div id = "repeater-target-basic" >
< input type = "text" class = "kt-input" placeholder = "Enter item" />
</ div >
</ div >
< p class = "mt-3 text-end" >
< button
type = "button"
class = "kt-btn kt-btn-outline kt-btn-sm inline-flex items-center gap-x-1"
data-kt-repeater = "true"
data-kt-repeater-target = "#repeater-target-basic"
data-kt-repeater-wrapper = "#repeater-wrapper-basic"
data-kt-repeater-limit = "3"
>
< svg
class = "shrink-0 size-3.5"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add item
</ button >
</ p >
</ div >
Predefined Markup
The template lives in a hidden container; only clones appear in the wrapper when you click "Add row".
< div class = "max-w-xs w-full" >
< div id = "repeater-wrapper-predefined" class = "space-y-3" ></ div >
< p class = "mt-3 text-end" >
< button
type = "button"
class = "kt-btn kt-btn-outline kt-btn-sm inline-flex items-center gap-x-1"
data-kt-repeater = "true"
data-kt-repeater-target = "#repeater-template-inner"
data-kt-repeater-wrapper = "#repeater-wrapper-predefined"
data-kt-repeater-limit = "3"
>
< svg
class = "shrink-0 size-3.5"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add row
</ button >
</ p >
< div id = "repeater-template-predefined" class = "hidden" >
< div id = "repeater-template-inner" >
< input type = "text" class = "kt-input" placeholder = "Enter value" />
</ div >
</ div >
</ div >
With Delete
Each cloned block includes a remove control. Use data-kt-repeater-delete on the element that should remove its block.
< div class = "max-w-xs w-full" >
< div id = "repeater-wrapper-delete" class = "space-y-3" >
< div id = "repeater-target-delete" class = "relative" >
< input type = "text" class = "kt-input pe-8" placeholder = "Enter tag" />< button
type = "button"
class = "kt-btn kt-btn-icon kt-btn-ghost size-6 absolute end-1 top-1/2 -translate-y-1/2 text-destructive"
data-kt-repeater-delete = "true"
aria-label = "Remove"
>
< svg
class = "shrink-0 size-4"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< circle cx = "12" cy = "12" r = "10" ></ circle >
< path d = "m15 9-6 6" ></ path >
< path d = "m9 9 6 6" ></ path >
</ svg >
</ button >
</ div >
</ div >
< p class = "mt-3 text-end" >
< button
type = "button"
class = "kt-btn kt-btn-outline kt-btn-sm inline-flex items-center gap-x-1"
data-kt-repeater = "true"
data-kt-repeater-target = "#repeater-target-delete"
data-kt-repeater-wrapper = "#repeater-wrapper-delete"
data-kt-repeater-limit = "3"
>
< svg
class = "shrink-0 size-3.5"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add tag
</ button >
</ p >
</ div >
On Modal
Use a repeater inside a modal to collect multiple items (e.g. guests) before submitting. Open the modal, add or remove rows, then submit or cancel.
< div >
< button class = "kt-btn" data-kt-modal-toggle = "#repeater-modal" >
Add guests
</ button >
< div class = "kt-modal" data-kt-modal = "true" id = "repeater-modal" >
< div class = "kt-modal-content max-w-[400px] top-[5%]" >
< div class = "kt-modal-header" >
< h3 class = "kt-modal-title" >Add guests</ h3 >
< button
type = "button"
class = "kt-modal-close"
aria-label = "Close modal"
data-kt-modal-dismiss = "#repeater-modal"
>
< svg
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
class = "lucide lucide-x"
aria-hidden = "true"
>
< path d = "M18 6 6 18" ></ path >
< path d = "m6 6 12 12" ></ path >
</ svg >
</ button >
</ div >
< div class = "kt-modal-body" >
< div id = "repeater-wrapper-modal" class = "space-y-3" >
< div id = "repeater-target-modal" class = "relative" >
< input
type = "text"
class = "kt-input pe-8 w-full"
placeholder = "Enter Name"
/>< button
type = "button"
class = "kt-btn kt-btn-icon kt-btn-ghost size-6 absolute end-1 top-1/2 -translate-y-1/2 text-destructive"
data-kt-repeater-delete = "true"
aria-label = "Remove"
>
< svg
class = "shrink-0 size-4"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< circle cx = "12" cy = "12" r = "10" ></ circle >
< path d = "m15 9-6 6" ></ path >
< path d = "m9 9 6 6" ></ path >
</ svg >
</ button >
</ div >
</ div >
< p class = "mt-3 text-end" >
< button
type = "button"
class = "kt-btn kt-btn-outline kt-btn-sm inline-flex items-center gap-x-1"
data-kt-repeater = "true"
data-kt-repeater-target = "#repeater-target-modal"
data-kt-repeater-wrapper = "#repeater-wrapper-modal"
data-kt-repeater-limit = "5"
>
< svg
class = "shrink-0 size-3.5"
xmlns = "http://www.w3.org/2000/svg"
width = "24"
height = "24"
viewBox = "0 0 24 24"
fill = "none"
stroke = "currentColor"
stroke-width = "2"
stroke-linecap = "round"
stroke-linejoin = "round"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add guest
</ button >
</ p >
</ div >
< div class = "kt-modal-footer" >
< div ></ div >
< div class = "flex gap-2" >
< button
type = "button"
class = "kt-btn kt-btn-secondary"
data-kt-modal-dismiss = "#repeater-modal"
>
Cancel</ button
>< button type = "button" class = "kt-btn" >Submit</ button >
</ div >
</ div >
</ div >
</ div >
</ div >
Component API
Options
These data attributes allow you to set options for the Repeater component during auto initialization. Set them on the trigger element (the element with data-kt-repeater).
Option Type Default Description data-kt-repeater-targetstring-CSS selector for the template element to clone (e.g. #my-template). data-kt-repeater-wrapper
Selectors
Name Description Data Attributes data-kt-repeaterOn the trigger element (e.g. button) to auto-initialize KTRepeater. Requires target and wrapper. data-kt-repeater-deleteOn an element inside a clone; click removes that clone from the wrapper.
Methods
Use KTRepeater component's API methods to programmatically control its behavior.
Method Description new KTRepeater(element, options)Creates a KTRepeater instance for the given trigger element and configuration options. add()Programmatically adds one clone (same as clicking the trigger). getOption(name)Returns the value of the named option (target, wrapper, limit).
const triggerEl = document. querySelector ( '#my_repeater_trigger' );
const repeater = KTRepeater. getInstance (triggerEl);
if (repeater) repeater. add ();
Utilities
Method Description init()Initializes all elements with data-kt-repeater on the page. createInstances()Initializes repeater triggers that were added to the DOM after load. getInstance(element)Returns the KTRepeater instance for the given trigger element, or null.
KTRepeater. init ();
KTRepeater. createInstances ();
const triggerEl = document. querySelector ( '#my_repeater_trigger' );
const repeater = KTRepeater. getInstance (triggerEl);
Events
Event Description addFired when a clone is added. Payload includes element (the cloned node). Use it to re-initialize nested components (e.g. KTSelect) on the new node.
const repeater = KTRepeater. getInstance (triggerEl);
repeater?. on ( 'add' , ( payload ) => {
KTSelect. createInstances (); // or init other components on payload.element
});
TypeScript
Import the component and types from @keenthemes/ktui:
import {
KTRepeater,
type KTRepeaterConfigInterface,
type KTRepeaterInterface,
} from '@keenthemes/ktui' ;
const triggerEl = document. querySelector < HTMLElement >( '#my_repeater_trigger' );
if ( ! triggerEl) return ;
const repeater : KTRepeaterInterface | null = KTRepeater. getInstance (triggerEl);
if (repeater) repeater. add ();
const options : KTRepeaterConfigInterface = {
target: '#template' ,
wrapper: '#container' ,
limit: