KTUIKTUI
KTUIKTUI
ComponentsDocsStudio

Getting Started

IntroductionInstallationApproachThemingJavaScriptTypeScriptDark modeRTLReferencesChangelog - v1.2.4Metronic TemplatePopular

Components

AccordionAvatarAlertBadgeBreadcrumbButtonCardCarouselNewClipboardNewCheckboxCollapseDatatableUpdateContext MenuNewDismissDrawerDropdownImage InputInputKbdLinkModalPaginationPin inputNewProgressRadio GroupRange SliderNewRatingNewReparentRepeaterNewScrollableScrollspyScrolltoSelectSeparatorSkeletonStepperStickySwitchTabsTextareaTheme SwitchToastTooltipToggleToggle GroupToggle PasswordTooltip
©2026 KtUI. All rights reserved.
A project by Keenthemes
Docs
Repeater

Repeater

Tailwind Repeater component adds repeatable form blocks. Click an "Add" button to clone a template into a container, with optional limit and per-item remove.

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

OptionTypeDefaultDescription
data-kt-repeater-targetstring-CSS selector for the template element to clone (e.g. #my-template).
data-kt-repeater-wrapper

Selectors

NameDescription
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.

MethodDescription
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

MethodDescription
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

EventDescription
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: 

PreviouseReparentNextScrollable

On This Page

  • Examples
    • Basic Usage
    • Predefined Markup
    • With Delete
    • On Modal
  • Component API
    • Options
    • Selectors
    • Methods
    • Utilities
    • Events
  • TypeScript
string
-
CSS selector for the container into which clones are appended.
data-kt-repeater-limitnumber0Maximum number of clones (0 = no limit). Trigger is disabled when at limit.
getElement()
Returns the trigger DOM element.
on(eventName, handler)Registers a listener for custom events. Returns an event id for use with off.
off(eventName, eventId)Removes a listener registered with on.
dispose()Removes the instance from the element and cleans up listeners.
getOrCreateInstance(element, config)
Returns the existing instance or creates one with the given config.
5
,
};
const instance: KTRepeaterInterface = KTRepeater.getOrCreateInstance(triggerEl, options);