Composables

useDataTable

Reactive table data, selection, sorting, filtering, pagination, and column state.

useDataTable provides the same Vue-native controller used by DataTable, without rendering a table. Use it for custom markup or a data workflow that needs table state outside a component.

If you already render DataTable, use its slot controller or exposed table instead of creating a second controller. A new useDataTable() call is an independent instance, not a lookup of an existing component.

Usage

Pass reactive data and columns, plus a stable row key. Destructure the returned refs when using them at the top level of a template; they unwrap there automatically.

<script setup lang="ts">
import type { DataTableColumn } from "akaza-ui";
import { useDataTable } from "akaza-ui";
import { ref } from "vue";

interface Person {
  id: string;
  name: string;
  email: string;
}

const data = ref<Person[]>([
  { id: "ada", name: "Ada Lovelace", email: "[email protected]" },
  { id: "grace", name: "Grace Hopper", email: "[email protected]" },
]);
const columns: DataTableColumn<Person>[] = [
  { accessor: "name", header: "Name" },
  { accessor: "email", header: "Email" },
];
const table = useDataTable({ data, columns, rowKey: "id" });
const { rows, globalFilter, columns: visibleColumns } = table;
</script>

<template>
  <label>
    Search people
    <input
      :value="globalFilter"
      @input="table.setGlobalFilter(($event.target as HTMLInputElement).value, $event)"
    >
  </label>
  <table>
    <caption>People</caption>
    <thead>
      <tr>
        <th
          v-for="column in visibleColumns"
          :key="column.id"
          scope="col"
          :aria-sort="column.sorted === 'asc' ? 'ascending' : column.sorted === 'desc' ? 'descending' : 'none'"
        >
          <button type="button" @click="table.toggleSorting(column.id, $event)">
            {{ column.definition.header }}
          </button>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="row in rows" :key="row.id">
        <td v-for="cell in table.getRowCells(row)" :key="cell.column.id">{{ cell.value }}</td>
      </tr>
      <tr v-if="!rows.length"><td colspan="2">No people found.</td></tr>
    </tbody>
  </table>
</template>

These columns use string headers. For grouped headers or custom renderers, use the controller's headerGroups and context helpers, or let DataTable render the structure through its slots.

Examples

Application-owned models

Supply refs when filters, selection, or pagination must also drive other controls. Use controller actions when changes should go through callbacks and cancellation.

import type { DataTablePaginationState, DataTableSelection } from "akaza-ui";
import { useDataTable } from "akaza-ui";
import { ref } from "vue";

const selection = ref<DataTableSelection>([]);
const pagination = ref<DataTablePaginationState>({ page: 1, pageSize: 20 });

const table = useDataTable({
  data,
  columns,
  rowKey: "id",
  selectionMode: "multiple",
  selection,
  paginate: true,
  pagination,
});

data and columns are the inputs from Usage. Pages are one-based. selectedRows contains matching loaded row instances; selection IDs may also include rows absent from a server page.

Reactive inputs

Pass refs or getters for replaceable collections and reactive options. Do not capture a current .value if you expect later replacements to be observed.

const table = useDataTable({
  data: () => response.value?.items ?? [],
  columns: () => configuredColumns.value,
  rowKey: "id",
  manualSorting: true,
  manualFiltering: true,
  manualPagination: true,
  rowCount: () => response.value?.total,
  pagination,
});

Your application fetches the page and reacts to model changes. The controller does not make requests. Manual flags prevent it from reprocessing results already sorted, filtered, or paginated by the server. See server-controlled data for the component workflow.

Cancel a change

Callbacks run before action-driven commits. Call details.cancel() to reject one. Direct model assignments are application-owned and do not invoke these callbacks.

const table = useDataTable({
  data,
  columns,
  rowKey: "id",
  paginate: true,
  pagination,
  onPaginationChange(_next, details) {
    if (saving.value) details.cancel();
  },
});

Callbacks receive the proposed value and { reason, event?, cancel }. onResetChange receives only the details object. Use the optional native event argument on actions to preserve the originating interaction.

API Reference

Signature

useDataTable<T extends object>(options: UseDataTableOptions<T>): DataTableController<T>;

Inputs and behavior options

MaybeRefOrGetter<T> means a plain value, ref, computed ref, or getter. Function-valued options such as rowKey and getSubRows are callbacks, not reactive getters.

OptionTypeDefaultDescription
dataMaybeRefOrGetter<readonly T[]>RequiredCurrent loaded rows.
columnsMaybeRefOrGetter<readonly DataTableColumn<T>[]>RequiredDefinitions; see column shape.
rowKeykeyof T & string or (row, index) => string | numberRequiredUnique stable key. Do not use a display index for changing datasets.
sortingModeMaybeRefOrGetter<'single' | 'multiple'>singleNumber of retained sort descriptors; multiple sorting uses a modified sort event.
manualSortingMaybeRefOrGetter<boolean>falseDo not sort data locally.
manualFilteringMaybeRefOrGetter<boolean>falseDo not filter data locally.
paginateMaybeRefOrGetter<boolean>falseEnable client pagination.
manualPaginationMaybeRefOrGetter<boolean>falseTreat loaded rows as a server page; enables pagination state.
rowCountMaybeRefOrGetter<number | undefined>Loaded row countTotal count for manual pagination.
selectionModeMaybeRefOrGetter<'none' | 'single' | 'multiple'>noneEnable selection actions.
selectAllScopeMaybeRefOrGetter<'page' | 'filtered'>pageScope for select-all actions. Server mode can only act on loaded rows.
isRowSelectable(row: T) => booleanAll rowsAllow selection per row.
isRowExpandable(row: T) => booleanHas child rowsAllow expansion per row, including application-owned details.
getSubRows(row: T) => readonly T[] | undefined-Return child rows.
columnResizeMaybeRefOrGetter<boolean | DataTableColumnResizeOptions>falseEnable resize actions and their behavior options.
dirMaybeRefOrGetter<'ltr' | 'rtl'>ltrLogical direction for column behavior.

ui, loading, error, stickyHeader, reorder handles, and row-click behavior are component/rendering options, not composable inputs.

Model refs

Each model accepts an optional writable ref. Omitting it creates internal state. These refs are also returned by the controller.

Option / return memberTypeInitial value when omitted
selectionRef<DataTableSelection>null
sortingRef<DataTableSorting[]>[]
filtersRef<DataTableFilters>{}
globalFilterRef<string>''
paginationRef<DataTablePaginationState>{ page: 1, pageSize: 10 }
expandedRef<DataTableRowKey[]>[]
columnVisibilityRef<DataTableColumnVisibility>{}; definitions also contribute default visibility
columnOrderRef<string[]>[]
columnSizingRef<DataTableColumnSizing>{}
columnPinningRef<DataTableColumnPinning>{ start: [], end: [] }; definitions also contribute default pins
rowOrderRef<DataTableRowKey[]>[]

Change callbacks

UseDataTableOptions extends DataTableChangeCallbacks. Every model has its matching callback:

onSelectionChange, onSortingChange, onFiltersChange, onGlobalFilterChange, onPaginationChange, onExpandedChange, onColumnVisibilityChange, onColumnOrderChange, onColumnSizingChange, onColumnPinningChange, and onRowOrderChange.

Each uses (nextValue, details) => void. onResetChange(details) can cancel reset before any model changes.

Derived state

MemberTypeDescription
columnsRead-only ref of DataTableColumnInstance<T>[]Current visible leaf columns in display order.
headerGroupsRead-only ref of DataTableHeaderGroup<T>[]Grouped header rows, including spans and placeholders.
rowsRead-only ref of DataTableRow<T>[]Display rows after enabled processing.
selectedRowsRead-only ref of DataTableRow<T>[]Selected row instances currently loaded.
filteredRowCountRead-only number refNumber of loaded rows in the filtered row model.
pageCountRead-only number refPage count; at least one, including empty results.
page, pageSizeRead-only number refsNormalized current page and page size.

Actions

The actions below return boolean; rejected, canceled, or inapplicable operations can return false. Optional event arguments accept a native event.

MethodArgumentsDescription
setFilter(columnId, value, event?)Set a column filter and reset the page when needed.
clearFilter(columnId, event?)Remove a column filter.
setGlobalFilter(value: string, event?)Set global search.
toggleSorting(columnId, event?)Cycle ascending, descending, and unsorted.
toggleRow(row, event?)Toggle a selectable row.
toggleAllRows(event?)Toggle selection for the configured scope in multiple mode.
toggleExpanded(row, event?)Toggle row details or children.
setPage(page: number, event?)Set a one-based page.
setPageSize(size: number, event?)Set page size and return to page one.
setColumnVisible(id, visible: boolean, event?)Show or hide a column.
setColumnPinned(id, side: false | 'start' | 'end', event?)Pin or unpin a column.
resizeColumn(id, size: number, event?)Apply a constrained width when resizing is enabled.
moveColumn(id, targetId, event?)Reorder columns by ID.
moveRow(id, targetId, event?)Reorder rows by stable key.
reset(event?)Clear selection, sorting, filters, expansion, sizing, and orders; return to page one while keeping page size, and restore definition-level visibility/pinning.

Lookup and render helpers

MethodReturn / behavior
getColumn(id)Public column instance or undefined.
getRow(id)Public loaded row instance or undefined.
getRowCells(row)Visible cell contexts for a row.
getCellContext(row, column)A DataTableCellContext<T>.
getHeaderContext(header)A DataTableHeaderContext<T>.
getHeaderAttrs(header)Consumer-supplied header attributes from the definition.
getCellAttrs(context)Consumer-supplied cell attributes from the definition.
getFooterAttrs(header)Consumer-supplied footer attributes from the definition.
isAllRowsSelected()Whether the selectable scope is fully selected.
isSomeRowsSelected()Whether the selectable scope is partially selected.

Attribute helpers do not generate complete ARIA or table semantics. Supply those in custom markup. Row instances expose original, stable id, display index, originalIndex, state flags, getValue, toggleSelected, and toggleExpanded. Column instances expose the definition, sizing, visibility, sorting, filtering, and pinning state. None exposes the underlying table engine.

Rendering, accessibility, and SSR

This composable owns data processing, not DOM. For custom tables, keep native table semantics, an accessible name or caption, scope on headers, sorting announcements, and labelled keyboard-operable controls. Pointer, touch, drag handles, focus, and visual feedback remain the renderer's responsibility. Use DataTable when you want those interactions supplied for you.

Create the controller in component setup so its reactive effects follow that component's lifetime. Data fetching and persistence remain application-owned. Pass stable, unique keys across client and server pages; replacing data does not mean a display index becomes a stable identity.