Examples
Basic Usage
Tailwind DataTable example that loads data from a local HTML table element and enables pagination and sorting features for the dataset
< div class = "grid w-full space-y-5" >
< div class = "kt-card" >
< div class = "kt-card-header min-h-16" >
< input
type = "text"
placeholder = "Search..."
class = "kt-input sm:w-48"
data-kt-datatable-search = "#kt_datatable_basic"
/>< button type = "button" class = "kt-btn kt-btn-outline" >
< 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-plus"
aria-hidden = "true"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add
</ button >
</ div >
< div
id = "kt_datatable_basic"
class = "kt-card-table"
data-kt-datatable = "true"
data-kt-datatable-page-size = "5"
data-kt-datatable-state-save = "true"
>
< div class = "kt-table-wrapper kt-scrollable" >
< table class = "kt-table" data-kt-datatable-table = "true" >
< thead >
< tr >
< th scope = "col" class = "w-30" data-kt-datatable-column = "label" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Label</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-20" data-kt-datatable-column = "method" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Method</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-24" data-kt-datatable-column = "status" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Status</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th
scope = "col"
class = "w-24"
data-kt-datatable-column = "lastSession"
>
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Last Session</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th
scope = "col"
class = "w-16"
data-kt-datatable-column = "actions"
></ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >Guy Hawkins</ td >
< td >Web</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >22 Jul 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Sales Dept</ td >
< td >SSH</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >18 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Sales Dept</ td >
< td >Kerberos</ td >
< td >< span class = "kt-badge kt-badge-primary" >Verified</ span ></ td >
< td >15 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Legal Dept</ td >
< td >Token</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >30 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Finance Dept</ td >
< td >API Key</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >28 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Design Dept</ td >
< td >FIDO U2F</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >16 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Compliance Dept</ td >
< td >OpenID</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >11 Aug, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Alice Smith</ td >
< td >Biometric</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >19 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >HR Dept</ td >
< td >Basic auth</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >6 Aug, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Guy Hawkins</ td >
< td >Web</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >22 Jul 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Sales Dept</ td >
< td >SSH</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >18 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Sales Dept</ td >
< td >Kerberos</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >15 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >Legal Dept</ td >
< td >Token</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >30 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
</ tbody >
</ table >
</ div >
<!--begin:pagination-->
< div class = "kt-datatable-toolbar" >
< div class = "kt-datatable-length" >
Show< select
class = "kt-select kt-select-sm w-16"
name = "perpage"
data-kt-datatable-size = "true"
></ select
>per page
</ div >
< div class = "kt-datatable-info" >
< span data-kt-datatable-info = "true" ></ span >
< div
class = "kt-datatable-pagination"
data-kt-datatable-pagination = "true"
></ div >
</ div >
</ div >
<!--end:pagination-->
</ div >
</ div >
</ div >
Remote Data Source
Tailwind DataTable example that loads data from a remote API endpoint and enables server-side pagination and sorting features for the dataset.
index.html demo.js
< div class = "grid w-full space-y-5" >
< div class = "kt-card" >
< div class = "kt-card-header min-h-16" >
< input
type = "text"
placeholder = "Search..."
class = "kt-input sm:w-48"
data-kt-datatable-search = "#kt_datatable_remote_source"
/>
</ div >
< div
id = "kt_datatable_remote_source"
class = "kt-card-table"
data-kt-datatable-page-size = "5"
data-kt-datatable-state-save = "true"
>
< div class = "kt-table-wrapper kt-scrollable" >
< table class = "kt-table" data-kt-datatable-table = "true" >
< thead >
< tr >
< th scope = "col" class = "w-30" data-kt-datatable-column = "label" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Label</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-20" data-kt-datatable-column = "method" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Method</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-24" data-kt-datatable-column = "status" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Status</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th
scope = "col"
class = "w-24"
data-kt-datatable-column = "lastSession"
>
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Last Session</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-24" data-kt-datatable-column = "ipAddress" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >IP Address</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
</ tr >
</ thead >
< tbody ></ tbody >
</ table >
</ div >
<!--begin:pagination-->
< div class = "kt-datatable-toolbar" >
< div class = "kt-datatable-length" >
Show< select
class = "kt-select kt-select-sm w-16"
name = "perpage"
data-kt-datatable-size = "true"
></ select
>per page
</ div >
< div class = "kt-datatable-info" >
< span data-kt-datatable-info = "true" ></ span >
< div
class = "kt-datatable-pagination"
data-kt-datatable-pagination = "true"
></ div >
</ div >
</ div >
<!--end:pagination-->
</ div >
</ div >
</ div >
Group Check
Tailwind DataTable example that enables group check features to easily select multiple table rows through a single checkbox.
< div class = "grid w-full space-y-5" >
< div class = "kt-card" >
< div class = "kt-card-header min-h-16" >
< input
type = "text"
placeholder = "Search..."
class = "kt-input sm:w-48"
data-kt-datatable-search = "#kt_datatable_group_check"
/>< button type = "button" class = "kt-btn kt-btn-outline" >
< 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-plus"
aria-hidden = "true"
>
< path d = "M5 12h14" ></ path >
< path d = "M12 5v14" ></ path ></ svg
>Add
</ button >
</ div >
< div
id = "kt_datatable_group_check"
class = "kt-card-table"
data-kt-datatable = "true"
data-kt-datatable-page-size = "5"
data-kt-datatable-state-save = "true"
>
< div class = "kt-table-wrapper kt-scrollable" >
< table class = "kt-table kt-table-border" data-kt-datatable-table = "true" >
< thead >
< tr >
< th scope = "col" class = "w-5" >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-check = "true"
/>
</ th >
< th scope = "col" class = "w-30" data-kt-datatable-column = "label" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Label</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-20" data-kt-datatable-column = "method" >
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Method</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th scope = "col" class = "w-24" data-kt-datatable-column = "status" >
< span class = "kt-table-col asc"
>< span class = "kt-table-col-label" >Status</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th
scope = "col"
class = "w-24"
data-kt-datatable-column = "lastSession"
>
< span class = "kt-table-col"
>< span class = "kt-table-col-label" >Last Session</ span
>< span class = "kt-table-col-sort" ></ span
></ span >
</ th >
< th
scope = "col"
class = "w-16"
data-kt-datatable-column = "actions"
></ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "0"
/>
</ td >
< td >Guy Hawkins</ td >
< td >Web</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >22 Jul 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "1"
/>
</ td >
< td >Sales Dept</ td >
< td >SSH</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >18 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "2"
/>
</ td >
< td >Sales Dept</ td >
< td >Kerberos</ td >
< td >< span class = "kt-badge kt-badge-primary" >Verified</ span ></ td >
< td >15 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "3"
/>
</ td >
< td >Legal Dept</ td >
< td >Token</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >30 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "4"
/>
</ td >
< td >Finance Dept</ td >
< td >API Key</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >28 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "5"
/>
</ td >
< td >Design Dept</ td >
< td >FIDO U2F</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >16 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "6"
/>
</ td >
< td >Compliance Dept</ td >
< td >OpenID</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >11 Aug, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "7"
/>
</ td >
< td >Alice Smith</ td >
< td >Biometric</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >19 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "8"
/>
</ td >
< td >HR Dept</ td >
< td >Basic auth</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >6 Aug, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "9"
/>
</ td >
< td >Guy Hawkins</ td >
< td >Web</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >22 Jul 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "10"
/>
</ td >
< td >Sales Dept</ td >
< td >SSH</ td >
< td >
< span class = "kt-badge kt-badge-destructive" >Rejected</ span >
</ td >
< td >18 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "11"
/>
</ td >
< td >Sales Dept</ td >
< td >Kerberos</ td >
< td >< span class = "kt-badge kt-badge-success" >Approved</ span ></ td >
< td >15 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
< tr >
< td >
< input
type = "checkbox"
class = "kt-checkbox"
data-kt-datatable-row-check = "true"
value = "12"
/>
</ td >
< td >Legal Dept</ td >
< td >Token</ td >
< td >< span class = "kt-badge kt-badge-warning" >Pending</ span ></ td >
< td >30 Jul, 2024</ td >
< td class = "text-end" >
< span class = "inline-flex gap-2.5"
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-pencil"
aria-hidden = "true"
>
< path
d = "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
></ path >
< path d = "m15 5 4 4" ></ path ></ svg ></ a
>< a
href = "#"
class = "kt-btn kt-btn-sm kt-btn-icon kt-btn-outline"
>< 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-trash"
aria-hidden = "true"
>
< path d = "M3 6h18" ></ path >
< path d = "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" ></ path >
< path
d = "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
></ path ></ svg ></ a
></ span >
</ td >
</ tr >
</ tbody >
</ table >
</ div >
<!--begin:pagination-->
< div class = "kt-datatable-toolbar" >
< div class = "kt-datatable-length" >
Show< select
class = "kt-select kt-select-sm w-16"
name = "perpage"
data-kt-datatable-size = "true"
></ select
>per page
</ div >
< div class = "kt-datatable-info" >
< span data-kt-datatable-info = "true" ></ span >
< div
class = "kt-datatable-pagination"
data-kt-datatable-pagination = "true"
></ div >
</ div >
</ div >
<!--end:pagination-->
</ div >
</ div >
</ div >
How It Works
The DataTable component handles data display, sorting, pagination, and search for both local HTML tables and remote API endpoints.
Component Architecture
Core Component (KTDataTable class) - Manages the complete lifecycle including initialization, configuration, state management, and DOM manipulation
Checkbox Handler - Dedicated module for group selection and row checkbox management
Sort Handler - Handles column sorting for both local and remote data sources
Event System - Pub/sub pattern for lifecycle hooks and user interactions
State Management - Persistent state storage via localStorage for pagination, sorting, and selection
Data Flow
The component automatically detects and handles two distinct data modes:
Local Mode (Client-Side)
HTML Table → Extract Data → Apply Search → Apply Sort → Paginate → Render Copy
Remote Mode (Server-Side)
API Request → Fetch Data → Transform (mapResponse) → Render → Update Pagination Copy
Data Modes
The component automatically detects whether to use local or remote mode based on your configuration.
Local Data Mode
When to Use:
Static data from HTML tables
Small to medium datasets (< 1000 rows)
Client-side filtering and sorting requirements
No server-side API available
How It Works:
When no apiEndpoint is configured, the component operates in local mode:
Reads data from existing HTML <tbody> rows
Stores original data in component state
Applies all pagination, sorting, and search client-side
Re-renders filtered/sorted data back to the DOM
Example:
< div data-kt-datatable = "true" data-kt-datatable-page-size = "10" >
< table class = "kt-table" data-kt-datatable-table = "true" >
< thead >
< tr >
< th data-kt-datatable-column = "name" >
< span class = "kt-table-col" >
< span class = "kt-table-col-label" >Name</ span >
< span class = "kt-table-col-sort" ></ span >
</ span >
</ th >
<!-- more columns -->
</ tr >
</ thead >
< tbody >
< tr >
< td >John Doe</ td >
<!-- more cells -->
</ tr >
<!-- more rows -->
</ tbody >
</ table >
</ div > Copy
Performance Considerations:
Initial load reads all data from DOM (one-time operation)
Filtering and sorting operate on in-memory arrays (fast)
Re-rendering limited to visible page (efficient)
State persistence adds minimal overhead via localStorage
Remote Data Mode
When to Use:
Large datasets (> 1000 rows)
Server-side pagination, filtering, and sorting
Dynamic data that changes frequently
RESTful API integration
How It Works:
When apiEndpoint is configured, the component operates in remote mode:
Makes HTTP requests to the API endpoint
Sends pagination, sort, and search parameters
Receives paginated data and total count
Renders only the current page
Updates pagination controls based on total count
Example:
const datatable = new KTDataTable (element, {
apiEndpoint: 'https://api.example.com/data' ,
requestMethod: 'GET' ,
requestHeaders: {
'Content-Type' : 'application/json' ,
'Authorization' : 'Bearer token123'
},
requestCredentials: 'include' , // Include cookies for session-based auth
pageSize: 20 ,
// Transform API response if needed
mapResponse : ( response ) => ({
data: response.items,
totalCount: response.total
})
}); Copy
API Request Parameters:
The component automatically sends these query parameters:
page - Current page number (1-based)
size - Number of records per page
sortField - Column name to sort by (when sorting active)
sortOrder - Sort direction (asc, desc, or empty string)
search - Search query string or JSON object (when search active)
filters - JSON string of column filters (when filters active)
Expected API Response Format:
{
"data" : [
{ "id" : 1 , "name" : "John" , "email" : "john@example.com" },
{ "id" : 2 , "name" : "Jane" , "email" : "jane@example.com" }
],
"totalCount" : 150
} Copy
Credentials Configuration
The requestCredentials option controls whether cookies, authorization headers, or TLS client certificates are included with fetch requests. This is essential for APIs that use session-based authentication.
Available Values:
"omit" - Never include credentials in requests
"same-origin" - Include credentials only for same-origin requests (browser default)
"include" - Always include credentials, even for cross-origin requests
Session-Based Authentication Example:
const datatable = new KTDataTable (element, {
apiEndpoint: 'https://api.example.com/data' ,
requestCredentials: 'include' , // Send cookies for session auth
requestHeaders: {
'Content-Type' : 'application/json'
}
}); Copy
Cross-Origin Security Requirements:
When using requestCredentials: 'include' with cross-origin APIs, the server must:
Set Access-Control-Allow-Credentials: true header
Specify the exact origin in Access-Control-Allow-Origin header (wildcard * is not permitted)
For more information, see the MDN Fetch API credentials documentation .
Mode Detection
The component automatically detects the mode - no manual configuration required:
// Local mode (no apiEndpoint)
const localTable = new KTDataTable (element, {
pageSize: 10 ,
stateSave: true
});
// Remote mode (apiEndpoint provided)
const remoteTable = new KTDataTable (element, {
apiEndpoint: '/api/data' ,
pageSize: 10
}); Copy
You cannot manually switch modes after initialization. If you need to change the data source, dispose of the current instance and create a new one.
Local Data Guide
Use local mode for small to medium datasets where client-side operations are sufficient.
Using HTML Tables
Provide data directly in your HTML markup. The component extracts and manages it automatically.
< div data-kt-datatable = "true" data-kt-datatable-page-size = "5" >
< table class = "kt-table" data-kt-datatable-table = "true" >
< thead >
< tr >
< th data-kt-datatable-column = "name" >
< span class = "kt-table-col" >
< span class = "kt-table-col-label" >Name</ span >
< span class = "kt-table-col-sort" ></ span >
</ span >
</ th >
< th data-kt-datatable-column = "email" >
< span class = "kt-table-col" >
< span class = "kt-table-col-label" >Email</ span >
< span class = "kt-table-col-sort" ></ span >
</ span >
</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >John Doe</ td >
< td >john@example.com</ td >
</ tr >
< tr >
< td >Jane Smith</ td >
< td >jane@example.com</ td >
</ tr >
</ tbody >
</ table >
</ div > Copy
The component will:
Extract data from each <tr> in the <tbody>
Map each <td> to the corresponding column based on order
Apply pagination, showing only 5 rows per page
Enable sorting on columns with data-kt-datatable-column
Client-Side Behavior
In local mode, all operations happen in the browser:
Pagination:
Original data stored in memory
Only current page rendered in DOM
Fast navigation between pages
No server requests
Sorting:
Uses default alphanumeric sort
Can provide custom sort.callback for complex sorting
Instant sorting response
State persisted across page reloads
Search/Filtering:
Filters data array client-side
Uses default substring matching
Can provide custom search.callback for advanced filtering
Results update with configurable delay (default 500ms)
Custom Local Sorting
Provide a custom sort callback for specialized sorting logic:
const datatable = new KTDataTable (element, {
pageSize: 10 ,
sort: {
callback : ( data , sortField , sortOrder ) => {
return data. sort (( a , b ) => {
const aValue = a[sortField];
const bValue = b[sortField];
// Numeric sorting
if ( typeof aValue === 'number' ) {
return sortOrder === 'asc' ? aValue - bValue : bValue - aValue;
}
// Date sorting
if ( ! isNaN (Date. parse (aValue))) {
const dateA = new Date (aValue);
const dateB = new Date (bValue);
return sortOrder === 'asc'
? dateA - dateB
: dateB - dateA;
}
// Default string sorting
return sortOrder === 'asc'
? String (aValue). localeCompare ( String (bValue))
: String (bValue). localeCompare ( String (aValue));
});
}
}
}); Copy
Custom Local Search
Implement custom search logic for advanced filtering:
const datatable = new KTDataTable (element, {
search: {
delay: 300 , // Shorter delay for faster response
callback : ( data , searchQuery ) => {
const query = searchQuery. toLowerCase ();
return data. filter ( item => {
// Search across multiple fields
return (
item.name?. toLowerCase (). includes (query) ||
item.email?. toLowerCase (). includes (query) ||
item.department?. toLowerCase (). includes (query)
);
});
}
}
}); Copy
Connect a search input to the DataTable using the data-kt-datatable-search attribute:
<!-- Search input references the datatable container ID -->
< input
type = "text"
placeholder = "Search..."
data-kt-datatable-search = "#my_datatable"
/>
<!-- Datatable container must have matching ID -->
< div id = "my_datatable" data-kt-datatable = "true" >
< table class = "kt-table" data-kt-datatable-table = "true" >
<!-- table markup -->
</ table >
<!-- pagination controls -->
</ div > Copy
The search will automatically:
Debounce input by 500ms (configurable via search.delay)
Filter data using the search.callback function (or default substring matching)
Reset to page 1 when search is applied
Persist search state when stateSave is enabled
Important: The data-kt-datatable-search value must be a CSS selector (starting with # for IDs) that matches the DataTable container element.
Best Practices:
Local mode suitable for up to ~1000 rows
Beyond 1000 rows, use remote mode
Enable state persistence for better UX
Use debounced search to reduce filtering overhead
Column Configuration
Customize how each column is displayed and behaves using the columns configuration object.
Basic Column Customization
Define custom rendering for specific columns:
const datatable = new KTDataTable (element, {
columns: {
status: {
title: 'Status' ,
render : ( value , row , context ) => {
// Return HTML string
const badgeClass = value === 'active' ? 'kt-badge-success' : 'kt-badge-destructive' ;
return `<span class="kt-badge ${ badgeClass }">${ value }</span>` ;
}
},
actions: {
render : ( value , row , context ) => {
// Return HTML for action buttons
return `
<div class="flex gap-2">
<button class="kt-btn kt-btn-sm" data-id="${ row . id }">Edit</button>
<button class="kt-btn kt-btn-sm kt-btn-destructive" data-id="${ row . id }">Delete</button>
</div>
` ;
}
}
}
}); Copy
Render Function Signatures
The render callback receives three parameters and can return different types:
render : (
cellData: any, // Value of this cell
rowData: object, // Complete row data object
context: KTDataTable // DataTable instance
) => string | HTMLElement | DocumentFragment Copy
Return Types:
HTML String (most common):
render : ( value , row ) => {
return `<span class="text-primary">${ value }</span>` ;
} Copy
⚠️ Security Warning: Be careful with user-generated content. Always sanitize HTML strings to prevent XSS attacks.
DOM Element:
render : ( value , row ) => {
const span = document. createElement ( 'span' );
span.className = 'kt-badge' ;
span.textContent = value; // Automatically escapes content
return span;
} Copy
Document Fragment:
render : ( value , row ) => {
const fragment = document. createDocumentFragment ();
const icon = document. createElement ( 'i' );
icon.className = 'icon-check' ;
const text = document. createTextNode (value);
fragment. appendChild (icon);
fragment. appendChild (text);
return fragment;
} Copy
CreatedCell Callback
For post-render cell manipulation, use createdCell:
const datatable = new KTDataTable (element, {
columns: {
email: {
createdCell : ( cell , cellData , rowData , row ) => {
// Add custom classes
cell.classList. add ( 'text-primary' , 'font-medium' );
// Attach event listeners
cell. addEventListener ( 'click' , () => {
console. log ( 'Email clicked:' , cellData);
});
// Add data attributes
cell.dataset.email = cellData;
// Add tooltips or popovers
cell. setAttribute ( 'title' , `Send email to ${ cellData }` );
}
},
actions: {
createdCell : ( cell , cellData , rowData , row ) => {
// Attach click handlers to action buttons
const editBtn = cell. querySelector ( '[data-action="edit"]' );
const deleteBtn = cell. querySelector ( '[data-action="delete"]' );
editBtn?. addEventListener ( 'click' , () => {
console. log ( 'Edit row:' , rowData.id);
});
deleteBtn?. addEventListener ( 'click' , () => {
console. log ( 'Delete row:' , rowData.id);
});
}
}
}
}); Copy
Nested Object Fields
Access nested properties in your data:
// Data structure with nested objects
const data = [
{
id: 1 ,
user: {
name: 'John Doe' ,
profile: {
avatar: '/avatars/john.jpg'
}
},
metadata: {
createdAt: '2024-01-15'
}
}
];
// Column configuration
const datatable = new KTDataTable (element, {
columns: {
'user.name' : {
title: 'User Name' ,
render : ( value , row ) => {
// Access nested data through row object
const avatarUrl = row.user?.profile?.avatar || '/default-avatar.jpg' ;
return `
<div class="flex items-center gap-2">
<img src="${ avatarUrl }" class="w-8 h-8 rounded-full" />
<span>${ value }</span>
</div>
` ;
}
}
}
}); Copy
Custom CSS Classes
Apply custom styling to cells:
const datatable = new KTDataTable (element, {
columns: {
priority: {
render : ( value ) => value,
createdCell : ( cell , cellData ) => {
// Conditional styling based on value
const colorClasses = {
high: 'bg-red-50 text-red-700' ,
medium: 'bg-yellow-50 text-yellow-700' ,
low: 'bg-green-50 text-green-700'
};
cell.className = `px-3 py-1 rounded ${ colorClasses [ cellData ] || ''}` ;
}
}
}
}); Copy
Advanced Configuration
Advanced configuration options for complex use cases.
Transform API responses to match the expected format:
const datatable = new KTDataTable (element, {
apiEndpoint: '/api/users' ,
mapResponse : ( response ) => {
// Handle different API response formats
// Case 1: Nested data structure
if (response.result && response.result.items) {
return {
data: response.result.items,
totalCount: response.result.pagination.total
};
}
// Case 2: Data in meta object
if (response.data && response.meta) {
return {
data: response.data,
totalCount: response.meta.total_count
};
}
// Case 3: Laravel pagination format
if (response.data && response.last_page) {
return {
data: response.data,
totalCount: response.total,
page: response.current_page,
pageSize: response.per_page,
totalPages: response.last_page
};
}
// Default format
return {
data: response.data || [],
totalCount: response.totalCount || response.total || 0
};
}
}); Copy
API Request Customization
Customize query parameters sent to the API:
const datatable = new KTDataTable (element, {
apiEndpoint: '/api/data' ,
mapRequest : ( params ) => {
// Rename parameters for your API
const page = params. get ( 'page' );
const size = params. get ( 'size' );
const sortField = params. get ( 'sortField' );
const sortOrder = params. get ( 'sortOrder' );
const search = params. get ( 'search' );
// Create new params object
const newParams = new URLSearchParams ();
// Map to your API's parameter names
newParams. set ( 'pageNumber' , page || '1' );
newParams. set ( 'pageLimit' , size || '10' );
if (sortField) {
newParams. set ( 'orderBy' , sortField);
newParams. set ( 'orderDirection' , sortOrder === 'asc' ? 'ascending' : 'descending' );
}
if (search) {
newParams. set ( 'q' , search);
}
// Add custom parameters
newParams. set ( 'includeDeleted' , 'false' );
newParams. set ( 'format' , 'json' );
return newParams;
}
}); Copy
Loading State Customization
Customize the loading indicator:
const datatable = new KTDataTable (element, {
loading: {
template: `
<div class="flex flex-col items-center justify-center py-12">
<div class="spinner-border animate-spin w-12 h-12 border-4 border-primary rounded-full border-t-transparent"></div>
<p class="mt-4 text-gray-600">{content}</p>
</div>
` ,
content: 'Loading data, please wait...'
}
}); Copy
Custom Selectors
Override default selectors (defaults shown):
const datatable = new KTDataTable (element, {
attributes: {
table: 'table[data-kt-datatable-table="true"]' ,
info: '[data-kt-datatable-info="true"]' ,
size: '[data-kt-datatable-size="true"]' ,
pagination: '[data-kt-datatable-pagination="true"]' ,
spinner: '[data-kt-datatable-spinner="true"]' ,
check: '[data-kt-datatable-check="true"]' ,
checkbox: '[data-kt-datatable-row-check="true"]'
}
}); Copy
Complete Configuration Example
A comprehensive example with all available options:
const datatable = new KTDataTable (element, {
// Remote data configuration
apiEndpoint: 'https://api.example.com/users' ,
requestMethod: 'GET' ,
requestHeaders: {
'Content-Type' : 'application/json' ,
'Authorization' : 'Bearer YOUR_TOKEN'
},
// Transform API response
mapResponse : ( response ) => ({
data: response.items,
totalCount: response.total
}),
// Customize query parameters
mapRequest : ( params ) => {
params. set ( 'include' , 'profile,permissions' );
return params;
},
// Pagination settings
pageSize: 20 ,
pageSizes: [ 10 , 20 , 50 , 100 ],
pageMore: true ,
pageMoreLimit: 5 ,
// State management
stateSave: true ,
stateNamespace: 'users-datatable' ,
// Column customization
columns: {
name: {
title: 'Full Name' ,
render : ( value , row ) => `
<div class="flex items-center gap-2">
<img src="${ row . avatar }" class="w-8 h-8 rounded-full" />
<span>${ value }</span>
</div>
`
},
status: {
render : ( value ) => {
const badge = value === 'active' ? 'kt-badge-success' : 'kt-badge-destructive' ;
return `<span class="kt-badge ${ badge }">${ value }</span>` ;
}
},
actions: {
render : ( value , row ) => `
<button class="kt-btn kt-btn-sm" data-id="${ row . id }">Edit</button>
` ,
createdCell : ( cell , cellData , rowData ) => {
cell. querySelector ( 'button' )?. addEventListener ( 'click' , () => {
console. log ( 'Edit:' , rowData);
});
}
}
},
// Search configuration
search: {
delay: 300 ,
callback : ( data , query ) => {
return data. filter ( item =>
item.name. toLowerCase (). includes (query. toLowerCase ())
);
}
},
// Sort configuration
sort: {
classes: {
base: 'kt-table-col' ,
asc: 'asc' ,
desc: 'desc'
},
callback : ( data , field , order ) => {
return data. sort (( a , b ) => {
const comparison = String (a[field]). localeCompare ( String (b[field]));
return order === 'asc' ? comparison : - comparison;
});
}
},
// Checkbox configuration
checkbox: {
checkedClass: 'bg-primary-50' ,
preserveSelection: true
},
// Loading customization
loading: {
template: '<div class="spinner">{content}</div>' ,
content: 'Loading...'
},
// Info template
info: 'Showing {start} to {end} of {total} entries' ,
infoEmpty: 'No data available' ,
// Custom selectors (if needed)
attributes: {
table: '[data-kt-datatable-table]' ,
info: '[data-kt-datatable-info]' ,
size: '[data-kt-datatable-size]' ,
pagination: '[data-kt-datatable-pagination]'
}
});
// Attach event listeners
datatable. on ( 'init' , () => console. log ( 'Initialized' ));
datatable. on ( 'fetched' , () => console. log ( 'Data fetched' ));
datatable. on ( 'sort' , ( event ) => console. log ( 'Sorted:' , event.detail)); Copy
Components API
Options
These options allow you to set options for the datatable component during auto initialization.
Option Type Default Description Data Options data-kt-datatable-state-savebooleantrueSaves the state of the DataTable (e.g., pagination, sorting) so it can be restored when the user returns to the page. data-kt-datatable-page-sizenumber10Sets the number of records to display per page in the DataTable. This value can be customized as needed. JavaScript Options requestMethodenum"GET"Defines the HTTP request method to be used for data fetching. requestHeadersobject{"Content-Type": "application/x-www-form-urlencoded"}Specifies the headers to be sent with the request. For more info, check JavaScript Request Headers . requestCredentialsenum"same-origin" (browser default)Controls whether cookies, authorization headers, or TLS client certificates are included with requests. Values: "omit", "same-origin", or "include". See Credentials Configuration for details. infostring"{start}-{end} of {total}"Template for displaying the current page information in the DataTable. infoEmptystring"No records found"Message displayed when no records are found in the DataTable. pageSizesarray[5, 10, 20, 30, 50]Defines the available page size options for the DataTable. pageSizenumber10Sets the default number of records displayed per page. pageMorebooleantrueDisplays a more pages ... indicator if the number of pages exceeds the pageMoreLimit value. pageMoreLimitnumber3Sets the threshold for displaying the "more pages" indicator. paginationobjectsee codePagination options for controlling the DataTable navigation. sortobjectsee codeSorting options for configuring how DataTable columns are sorted. searchobjectsee codeSearching options for configuring how DataTable columns are filtered when searching. loadingobjectsee codeLoading options to manage the DataTable loading state. attributesobjectsee codeSpecifies the selectors for the elements to be targeted. stateSavebooleantrueEnables saving the state of the DataTable (e.g., pagination, sorting) for persistence across page reloads. stateNamespacestringcomponent IDNamespace for localStorage keys. Use unique values for multiple datatables on the same page. columnsobjectundefinedOptional. Defines custom column rendering and cell creation logic. Advanced Options apiEndpointstringundefinedURL of the API endpoint for remote data fetching. When provided, enables remote mode. mapResponsefunctionundefinedFunction to transform API response. Receives response data, must return {data: [], totalCount: number}. mapRequestfunctionundefinedFunction to customize query parameters. Receives URLSearchParams object, must return modified URLSearchParams. sort.callbackfunctiondefault sortCustom sorting function for local data. Receives (data, sortField, sortOrder), must return sorted array. search.callbackfunctiondefault searchCustom search function for local data. Receives (data, searchQuery), must return filtered array. search.delaynumber500Debounce delay in milliseconds before applying search filter. checkbox.checkedClassstring"checked"CSS class to apply to checked rows. checkbox.preserveSelectionbooleantrueWhether to preserve selection across page changes and data reloads.
Selectors
This table details the custom classes and data attributes used by the DataTable component.
Name Description Data Attributes data-kt-datatableUsed to auto-initialize KTDataTable instances on page load. Alternatively, you can remove it and perform initialization using JavaScript. data-kt-datatable-tableIdentifies the main table element for the DataTable. data-kt-datatable-columnUsed on <th> elements to identify columns. data-kt-datatable-column-sortUsed on <th> elements to enable sorting for that column. data-kt-datatable-searchUsed on <input> elements to connect a search field to a DataTable. Value must be a CSS selector (e.g., "#my_datatable") matching the DataTable container's id attribute. data-kt-datatable-checkIdentifies the group checkbox control used to select multiple rows. data-kt-datatable-row-checkIdentifies the individual checkbox control for each row. data-kt-datatable-infoIdentifies the element that displays the current page number and total pages. data-kt-datatable-sizeMarks the select control that allows users to change the number of records displayed per page. data-kt-datatable-paginationIdentifies the pagination element that enables users to navigate through different pages. Classes kt-tableBase class for the DataTable element. It wraps the entire table content and provides basic styling and behavior. kt-table-gridAdds border styling to the DataTable for visual separation and emphasis. kt-table-sortEnables sorting functionality for the DataTable columns. kt-table-sort-labelApplied to the label element within the sortable column to indicate sorting. kt-table-sort-iconApplied to the icon element within the sortable column to visually represent sorting direction. ascIndicates that a column in the DataTable is sorted in ascending order. descIndicates that a column in the DataTable is sorted in descending order.
Tailwind Modifiers
Custom modifiers to control the DataTable's style and behavior with Tailwind classes.
Name Description kt-datatable-loadingApplies specific styles when the DataTable is loading, triggered by actions such as pagination, page size change, or sorting. kt-datatable-initializedApplies specific styles when the DataTable has fully initialized and is ready for user interaction. kt-datatable-sort-ascApplies specific styles when a column in the DataTable is sorted in ascending order. kt-datatable-sort-descApplies specific styles when a column in the DataTable is sorted in descending order.
Methods
Use KTDataTable component's API methods to programmatically control its behavior.
Method Description new KTDataTable(element, options)Creates an instance of the KTDataTable class for the given DOM element and configuration options. This initializes the DataTable with the specified settings and binds it to the provided HTML element. sort(field: string | number)Sorts the DataTable based on the specified field, which can be a column name string or column index number. This method reorders the rows according to the sort criteria applied to the field. search(query: string | object)Searches the DataTable for rows that match the specified text string or object. This method filters the rows to display only those that contain the search query. goPage(page: number)Navigates to the specified page number in the DataTable. This method updates the displayed rows to correspond with the chosen page. reload()Reloads the DataTable data. This method refreshes the DataTable, fetching the latest data and updating the display accordingly. setPageSize(pageSize: number)Sets the number of records to display per page in the DataTable. This method adjusts the pagination settings to accommodate the specified page size. redraw(page: number)Redraws the DataTable at the specified page number. Useful for manual pagination updates. setFilter(filter: object)Sets a column filter. Accepts an object with column, type, and value properties. showSpinner()Displays a loading spinner overlay on the DataTable. This method is useful for indicating that data is being loaded or processed. hideSpinner()Hides the loading spinner overlay from the DataTable. This method is used to indicate that data loading or processing is complete. dispose()Removes the KTDataTable instance from an element, including any associated data stored on the DOM element. isChecked()Returns true if the group checkbox is checked, otherwise false. toggle()Toggles the group checkbox state between checked and unchecked. check()Checks all visible row checkboxes. uncheck()Unchecks all visible row checkboxes. getChecked()Returns an array of the checked row IDs. update()Reapplies checked state to visible checkboxes (after redraw/pagination). getState()Returns the current state object of the DataTable.
const datatableEl = document. querySelector ( '#my_datatable' );
const options = {
pageSize: 5 ,
stateSave: true ,
};
const datatable = new KTDataTable (datatableEl, options);
datatable. reload ();
datatable. showSpinner (); Copy
Utilities
Manage and interact with KTDataTable instances using these static methods of the KTDataTable JavaScript class.
Method Description init()Automatically initializes KTDataTable objects for all elements with the data-kt-datatable="true" attribute on page load. createInstances()Creates KTDataTable instances for all elements that have been dynamically added to the DOM but haven't been activated yet. getInstance(element)Returns the KTDataTable object associated with the given DOM element element.
// Initialize all datatables
KTDataTable. init ();
// Initialize pending datatables
KTDataTable. createInstances ();
// Get datatable object
const datatableEl = document. querySelector ( '#my_datatable' );
const datatable = KTDataTable. getInstance (datatableEl); Copy
Events
KTDataTable custom events allow you to register callback functions (event listeners) that will be invoked automatically whenever specific custom events are triggered within the component.
Event Description initTriggered immediately after the DataTable is initialized. drawTriggered immediately before the DataTable is drawn and displayed. drewTriggered immediately after the DataTable is drawn and displayed. redrawTriggered immediately after the DataTable is redrawn, typically after updates or changes. fetchTriggered immediately before data is fetched for the DataTable. fetchedTriggered immediately after data has been fetched for the DataTable. sortTriggered immediately after the DataTable is sorted. checkedTriggered immediately after rows checkbox is checked. uncheckedTriggered immediately after rows checkbox is unchecked. changedTriggered after any checkbox state change, in addition to checked/unchecked events. changeTriggered before checkbox state changes. Can be cancelled by setting event.detail.cancel = true. reloadTriggered immediately after the DataTable is reloaded. paginationTriggered immediately before the DataTable pagination is updated. stateSaveTriggered immediately before the DataTable state is saved. errorTriggered if there is an error during data fetching or processing. parseErrorTriggered when JSON parsing of API response fails (remote mode only).
const datatableEl = document. querySelector ( '#my_datatable' );
const options = {
pageSize: 5 ,
stateSave: true ,
};
const datatable = new KTDataTable (datatableEl, options);
datatable. on ( 'init' , () => {
console. log ( 'init event' );
});
datatable. on ( 'draw' , () => {
console. log ( 'draw event' );
}); Copy
Event Usage Patterns
Lifecycle Events - Show Loading Indicators:
const datatable = new KTDataTable (element, options);
const loadingOverlay = document. querySelector ( '#loading-overlay' );
// Show loading on data fetch
datatable. on ( 'fetch' , () => {
loadingOverlay.classList. remove ( 'hidden' );
});
// Hide loading when data loaded
datatable. on ( 'fetched' , () => {
loadingOverlay.classList. add ( 'hidden' );
});
// Handle errors
datatable. on ( 'error' , ( event ) => {
loadingOverlay.classList. add ( 'hidden' );
console. error ( 'Error loading data:' , event.detail.error);
});
// Handle JSON parse errors (remote mode)
datatable. on ( 'parseError' , ( event ) => {
loadingOverlay.classList. add ( 'hidden' );
console. error ( 'Failed to parse response:' , {
status: event.detail.status,
statusText: event.detail.statusText,
error: event.detail.error
});
// Show user-friendly error message
alert ( 'Failed to load data. Please try again later.' );
}); Copy
Interaction Events - Track User Actions:
datatable. on ( 'sort' , ( event ) => {
const { field , order } = event.detail;
console. log ( `Table sorted by ${ field } in ${ order } order` );
// Send analytics event
analytics. track ( 'table_sorted' , { field, order });
});
datatable. on ( 'pagination' , ( event ) => {
const { page } = event.detail;
console. log ( `Navigated to page ${ page }` );
// Update URL without page reload
const url = new URL (window.location);
url.searchParams. set ( 'page' , page);
window.history. pushState ({}, '' , url);
});
datatable. on ( 'checked' , ( event ) => {
const checkedIds = datatable. getChecked ();
console. log ( `Selected ${ checkedIds . length } rows:` , checkedIds);
// Enable bulk actions
document. querySelector ( '#bulk-actions' ).disabled = false ;
});
datatable. on ( 'unchecked' , () => {
const checkedIds = datatable. getChecked ();
if (checkedIds. length === 0 ) {
// Disable bulk actions when nothing selected
document. querySelector ( '#bulk-actions' ).disabled = true ;
}
});
// Track all checkbox changes (fires for any check/uncheck)
datatable. on ( 'changed' , () => {
const checkedIds = datatable. getChecked ();
console. log ( `Selection changed. Currently selected: ${ checkedIds . length } rows` );
// Update UI based on selection count
const selectionCount = document. querySelector ( '#selection-count' );
selectionCount.textContent = `${ checkedIds . length } selected` ;
});
// Prevent checkbox changes conditionally (advanced)
datatable. on ( 'change' , ( event ) => {
const checkedIds = datatable. getChecked ();
// Prevent more than 10 selections
if (checkedIds. length >= 10 ) {
event.detail.cancel = true ;
alert ( 'Maximum 10 items can be selected' );
}
}); Copy
Data Manipulation After Render:
datatable. on ( 'drew' , () => {
// Attach tooltips to newly rendered elements
const tooltipElements = document. querySelectorAll ( '[data-tooltip]' );
tooltipElements. forEach ( el => {
new Tooltip (el);
});
// Initialize popovers
const popoverElements = document. querySelectorAll ( '[data-popover]' );
popoverElements. forEach ( el => {
new Popover (el);
});
// Highlight search terms
const searchQuery = datatable. getState ().search;
if (searchQuery) {
highlightSearchTerms (searchQuery);
}
}); Copy
Accessing DataTable Instance in Events:
datatable. on ( 'init' , function () {
// 'this' refers to the datatable instance
const state = this . getState ();
console. log ( 'Initial state:' , state);
// Call instance methods
if (state.page > 1 ) {
this . goPage ( 1 ); // Reset to first page
}
});
datatable. on ( 'fetched' , function () {
const state = this . getState ();
// Update external UI elements
document. querySelector ( '#total-records' ).textContent = state.totalItems;
// Apply custom processing
if (state.totalItems === 0 ) {
document. querySelector ( '#empty-state' ).classList. remove ( 'hidden' );
}
}); Copy
State Synchronization:
// Sync with external state management
datatable. on ( 'stateSave' , function () {
const state = this . getState ();
// Save to Vuex/Redux/custom store
store. commit ( 'SET_DATATABLE_STATE' , {
page: state.page,
pageSize: state.pageSize,
sortField: state.sortField,
sortOrder: state.sortOrder,
selectedRows: state.selectedRows
});
});
// Restore state on init
datatable. on ( 'init' , function () {
const savedState = store.state.datatableState;
if (savedState) {
this . goPage (savedState.page);
this . setPageSize (savedState.pageSize);
if (savedState.sortField) {
this . sort (savedState.sortField);
}
}
}); Copy
Event Parameter Details:
Event Event Detail Properties initnone drawnone drewnone redrawnone fetchnone fetched{ response } (remote mode only, first fire)sort{ field: string|number, order: 'asc'|'desc'|'' }checkednone (use getChecked() method to retrieve IDs)uncheckednone (use getChecked() method to retrieve IDs)changednone (use getChecked() method to retrieve IDs)change{ cancel: boolean } (set cancel: true to prevent change)reloadnone pagination{ page: number }stateSavenone (use getState() method to retrieve full state)error{ error }parseError{ response, error: string, status: number, statusText: string }