MonoStack
Functionalities

Data Display

Data grids with sorting, filtering, pagination, and URL state persistence.

Package: @repo/table Built on: TanStack Table

Basic Data Grid

<script lang="ts">
  import type { QueryDataPoint } from '@repo/table/remote'
  import { getUsersQuery } from '$lib/domains/users/database/users.remote'
  import { userFilterSchema } from '$lib/domains/users/utils/schemas'
  import { createColumnHelper, DataGrid, useDataGrid } from '@repo/table/remote'

  const ch = createColumnHelper<QueryDataPoint<typeof getUsersQuery>>()

  const { table, dataGrid } = useDataGrid({
    tableOptions: {
      columns: ch.columns([
        ch.accessor('name', {
          header: 'Name',
        }),
        ch.accessor('createdAt', {
          header: 'Created At',
          cell: ({ row }) => formatDate(row.original.createdAt, 'HH:mm dd-MM-yyyy'),
        }),
      ]),
      initialState: {
        sorting: [{ id: 'name', desc: false }],
      },
    },
    query: getUsersQuery,
    filterSchema: userFilterSchema,
    getRowLink: (row) => `users/${row.id}`,
  })
</script>

<DataGrid.Root title="Users" {table} {dataGrid} add="/users/add">
  <DataGrid.FilterForm schema={userFilterSchema} />
</DataGrid.Root>

Column Configuration

Use the feature-bound createColumnHelper exported by @repo/table/remote:

const ch = createColumnHelper<QueryDataPoint<typeof getUsersQuery>>()

const columns = ch.columns([
  ch.accessor('name', { header: 'Name' }),
  ch.accessor('email', { header: 'Email' }),
  ch.accessor('createdAt', {
    header: 'Joined',
    cell: ({ row }) => formatDate(row.original.createdAt, 'dd-MM-yyyy'),
  }),
])

Add Button

Pass a URL string or boolean to show an add button:

<!-- Link to add page -->
<DataGrid.Root title='Users' {table} {dataGrid} add='/users/add'>

<!-- Conditional add based on permissions -->
<DataGrid.Root title='Users' {table} {dataGrid} add={await hasAccess([createPermissionGate('users', ['create'])])}>

Server Query Definition

// users.remote.ts
import { query } from '$app/server'
import { createOverviewQuerySchema } from '@repo/table/remote'
import { overviewToQuery, countSelect } from '@repo/db'

export const getUsersQuery = query(createOverviewQuerySchema(userFilterSchema), async (data) => {
  await validateSession([createPermissionGate('users', ['list'])])
  const { db, usersTable } = await getTenantDb()

  return await overviewToQuery(
    db
      .select({
        id: usersTable.id,
        name: usersTable.name,
        createdAt: usersTable.createdAt,
        count: countSelect,
      })
      .from(usersTable)
      .$dynamic(),
    usersTable,
    data,
  )
})

Full Documentation

See @repo/table for complete API reference.

On this page