Skip to content

Table ​

Experimental

Display tabular data with sorting, filtering, and pagination powered by AgGrid.

Examples ​

Column Options ​

Configure column pinning, min/max widths via AgGrid's ColDef. Some common configurations include pinned: left/right, max/minWidth, resizable, sortable, cellClass

vue
<script setup lang="ts">
import { HTable } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const columnDefs: ColDef[] = [
  { field: 'id', width: 120, pinned: 'left', resizable: false },
  { field: 'name', minWidth: 150, maxWidth: 300 },
  { field: 'email', minWidth: 200 },
  { field: 'department', minWidth: 120, sortable: false },
  { field: 'status', width: 120, pinned: 'right' },
]

const rowData = [
  { id: 1, name: 'Alice Nguyen', email: '[email protected]', department: 'Engineering', status: 'Active' },
  { id: 2, name: 'Brian Tran', email: '[email protected]', department: 'Marketing', status: 'Pending' },
  { id: 3, name: 'Chloe Pham', email: '[email protected]', department: 'Sales', status: 'Inactive' },
  { id: 4, name: 'Daniel Vo', email: '[email protected]', department: 'Engineering', status: 'Active' },
]
</script>

<template>
  <HTable
    style="width: 100%;"
    :column-defs="columnDefs"
    :row-data="rowData"
  />
</template>

Quick Filter ​

Show a text input above the table for quick row filtering.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { HTable } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const columnDefs: ColDef[] = [
  { field: 'name' },
  { field: 'language' },
  { field: 'stars' },
]

const rowData = [
  { name: 'Vue', language: 'TypeScript', stars: 48000 },
  { name: 'React', language: 'JavaScript', stars: 230000 },
  { name: 'Angular', language: 'TypeScript', stars: 96000 },
  { name: 'Svelte', language: 'TypeScript', stars: 81000 },
  { name: 'Solid', language: 'TypeScript', stars: 33000 },
]

const filter = ref('')
</script>

<template>
  <HTable
    v-model:filter="filter"
    :column-defs="columnDefs"
    :row-data="rowData"
    quick-filter
    style="width: 100%;"
  />
</template>

Custom Filter Input ​

For a custom search UI, skip the quickFilter prop and pass quickFilterText directly via agGridOptions.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { HTable, HTextInput, HIcon } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const searchText = ref('')

const columnDefs: ColDef[] = [
  { field: 'name' },
  { field: 'email' },
  { field: 'department' },
  { field: 'status' },
]

const rowData = [
  {
    name: 'Alice Nguyen', email: '[email protected]', department: 'Engineering', status: 'Active',
  },
  {
    name: 'Brian Tran', email: '[email protected]', department: 'Marketing', status: 'Pending',
  },
  {
    name: 'Chloe Pham', email: '[email protected]', department: 'Sales', status: 'Inactive',
  },
  {
    name: 'Daniel Vo', email: '[email protected]', department: 'Engineering', status: 'Active',
  },
  {
    name: 'Evelyn Le', email: '[email protected]', department: 'Marketing', status: 'Active',
  },
]
</script>

<template>
  <div class="flex w-full flex-col gap-2">
    <HTextInput
      v-model="searchText"
      placeholder="Search by name, email..."
      class="w-64"
    >
      <template #prefix>
        <HIcon name="search" />
      </template>
    </HTextInput>

    <HTable
      :column-defs="columnDefs"
      :row-data="rowData"
      :ag-grid-options="{
        quickFilterText: searchText,
      }"
    />
  </div>
</template>

Pagination ​

Enable pagination with configurable page sizes.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { HTable } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const columnDefs: ColDef[] = [
  { field: 'id' },
  { field: 'name' },
  { field: 'status' },
]

const rowData = Array.from({ length: 50 }, (_, i) => ({
  id: i + 1,
  name: `Item ${i + 1}`,
  // eslint-disable-next-line no-nested-ternary
  status: i % 3 === 0 ? 'Active' : i % 3 === 1 ? 'Pending' : 'Inactive',
}))

const page = ref(1)
const pageSize = ref(10)
</script>

<template>
  <HTable
    v-model:page="page"
    v-model:pagination-page-size="pageSize"
    :column-defs="columnDefs"
    :row-data="rowData"
    pagination
    :pagination-page-size-selector="[10, 25, 50]"
    style="width: 100%;"
  />
</template>

Row Size ​

Use the rowSize prop to switch between pre-defined row heights: md (44px) and lg (64px).

vue
<script setup lang="ts">
import { ref } from 'vue'
import {
  HTable, HSegmentedControl, type SegmentedControlItem, type RowSize,
} from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const sizeItems: SegmentedControlItem<RowSize>[] = [
  { label: 'md (44px)', value: 'md' },
  { label: 'lg (64px)', value: 'lg' },
]

const rowSize = ref<RowSize>('md')

const columnDefs: ColDef[] = [
  { field: 'name' },
  { field: 'email' },
  { field: 'department' },
]

const rowData = [
  { name: 'Alice Nguyen', email: '[email protected]', department: 'Engineering' },
  { name: 'Brian Tran', email: '[email protected]', department: 'Marketing' },
  { name: 'Chloe Pham', email: '[email protected]', department: 'Sales' },
  { name: 'Daniel Vo', email: '[email protected]', department: 'Engineering' },
]
</script>

<template>
  <div class="flex w-full flex-col gap-2">
    <HSegmentedControl
      v-model="rowSize"
      :items="sizeItems"
    />

    <HTable
      :column-defs="columnDefs"
      :row-data="rowData"
      :row-size="rowSize"
    />
  </div>
</template>

Custom Cell Renderer ​

Use Vue components as cell renderers for rich cell content. The component receives params (of type ICellRendererParams) with access to the cell value and row data.

WARNING

  • When using CellRenderer, HRM will not work, we have to manual refresh the page
  • Dev tool cannot inspect CellRenderer components
vue
<script setup lang="ts">
import { HTable } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'
import StatusRenderer from './StatusRenderer.vue'

const columnDefs: ColDef[] = [
  { field: 'name' },
  { field: 'email' },
  {
    field: 'status',
    cellRenderer: StatusRenderer,
    cellClass: 'flex items-center',
  },
]

const rowData = [
  { name: 'Alice Nguyen', email: '[email protected]', status: 'Active' },
  { name: 'Brian Tran', email: '[email protected]', status: 'Pending' },
  { name: 'Chloe Pham', email: '[email protected]', status: 'Inactive' },
  { name: 'Daniel Vo', email: '[email protected]', status: 'Active' },
]
</script>

<template>
  <HTable
    style="width: 100%;"
    :column-defs="columnDefs"
    :row-data="rowData"
  />
</template>
vue
<script setup lang="ts">
import type { ICellRendererParams } from 'ag-grid-enterprise'
import { HBadge } from '@holistics/design-system'

defineProps<{
  params: ICellRendererParams
}>()

const typeMap: Record<string, typeof HBadge['type']> = {
  Active: 'success-primary',
  Pending: 'warning-primary',
  Inactive: 'default',
}
</script>

<template>
  <HBadge :type="typeMap[params.value]">
    {{ params.value }}
  </HBadge>
</template>

AgGrid Options ​

All other AgGrid options can be passed via the agGridOptions prop. See the AgGrid documentation for the full list.

vue
<script setup lang="ts">
import { HTable } from '@holistics/design-system'
import type { ColDef } from 'ag-grid-enterprise'

const columnDefs: ColDef[] = [
  { field: 'id' },
  { field: 'name' },
  { field: 'email' },
  { field: 'department' },
]

const rowData = [
  {
    id: 1, name: 'Alice Nguyen', email: '[email protected]', department: 'Engineering',
  },
  {
    id: 2, name: 'Brian Tran', email: '[email protected]', department: 'Marketing',
  },
  {
    id: 3, name: 'Chloe Pham', email: '[email protected]', department: 'Sales',
  },
  {
    id: 4, name: 'Daniel Vo', email: '[email protected]', department: 'Engineering',
  },
]
</script>

<template>
  <HTable
    style="width: 100%;"
    :column-defs="columnDefs"
    :row-data="rowData"
    :ag-grid-options="{
      rowSelection: { mode: 'multiRow' },
    }"
  />
</template>

Edge cases ​

  1. getRowId

    • Using getRowId will remove Vue's reactivity when accessing data via params - e.g. cell renderer's params (ICellRendererParams)
    • We need to use functions such as setData to update the row data
    • Known Issue
  2. Line height

    • AgGrid computes its line-height programmatically based on properties like row height, auto height, vertically padding ratio, etc. and we cannot set a fixed line-height
    • Therefore, in some places we need to overwrite with a line-height in order to make the content display correctly - e.g. using !text-sm in cellClass
  3. Auto height

    • By default, HTable uses autoHeight to fit the table into its container
    • AgGrid's autoHeight has a default min width of 150px, Holistics is currently overwriting it with a min width of 80px instead

API ​

Props ​

NameTypeDescription
rowData *
any[] | null

Set the data to be displayed as rows in the grid https://www.ag-grid.com/vue-data-grid/row-ids/

columnDefs *
(ColDef<any, any> | ColGroupDef<any>)[] | null

Array of Column / Column Group definitions https://www.ag-grid.com/vue-data-grid/column-definitions/

quickFilter 
boolean

Whether to show the text input for quick filter.

pagination 
boolean

Whether to show the pagination.

paginationPageSizeSelector 
number[]

Array of page size options.

stickyPreHeader 
boolean

Whether to make the pre-header sticky.

texts 
Texts

Custom texts for places such as filter, page size, no results, loading, etc.

wrapperClass 
HTMLAttributeClass

Custom class for the table container.

modules 
Module[]

Modules to be loaded into the grid. By default, all community modules are loaded. https://www.ag-grid.com/vue-data-grid/modules/

borders 
Borders

Border settings for the table. By default, row and header row borders are enabled.

theme 
Theme

Theme for the table. By default, the Holistics theme is used. https://www.ag-grid.com/vue-data-grid/theming/

overlayComponentSelector 
OverlaySelectorFunc

Custom component to be used as overlay. By default, a custom overlay component is used for loading and no results states. https://www.ag-grid.com/vue-data-grid/overlays-overview/

rowSize 
RowSize
= "md"

Pre-defined row size used for Holistics table theme. To customize row height, use AgGrid's rowHeight prop, which will override Holistics theme.

agGridOptions 
Omit<GridOptions<any>, "columnDefs" | "rowData">

All props from AgGridVue https://www.ag-grid.com/vue-data-grid/reference/

filter 
string
page 
number
= 1
paginationPageSize 
number
= 50

Events ​

NameParametersDescription
@update:filter
[value: string | undefined]
@update:page
[value: number]
@update:paginationPageSize
[value: number]
@gridReady
[params: GridReadyEvent<any, any>]
@paginationChanged
[params: { page: number; pageSize: number; }]

Slots ​

NameScopedDescription
#pre-header
{}

Exposed ​

NameTypeDescription
gridApi
GridApi<any> | undefined