<script lang="ts"> import { writable } from 'svelte/store' import { createSvelteTable, getCoreRowModel, getSortedRowModel, flexRender, } from '@tanstack/svelte-table' import type { ColumnDef, ColumnOrderState, ColumnPinningState, OnChangeFn, TableOptions, VisibilityState, } from '@tanstack/svelte-table' import { makeData, type Person } from './makeData' import { faker } from '@faker-js/faker' import './index.css' const columns: ColumnDef<Person>[] = [ { header: 'Name', footer: props => props.column.id, columns: [ { accessorKey: 'firstName', cell: info => info.getValue(), footer: props => props.column.id, }, { accessorFn: row => row.lastName, id: 'lastName', cell: info => info.getValue(), header: () => 'Last Name', footer: props => props.column.id, }, ], }, { header: 'Info', footer: props => props.column.id, columns: [ { accessorKey: 'age', header: () => 'Age', footer: props => props.column.id, }, { header: 'More Info', columns: [ { accessorKey: 'visits', header: () => 'Visits', footer: props => props.column.id, }, { accessorKey: 'status', header: 'Status', footer: props => props.column.id, }, { accessorKey: 'progress', header: 'Profile Progress', footer: props => props.column.id, }, ], }, ], }, ] const data = makeData(5000) let isSplit = false let columnOrder: ColumnOrderState = [] let columnPinning: ColumnPinningState = {} let columnVisibility: VisibilityState = {} const setColumnOrder: OnChangeFn<ColumnOrderState> = updater => { if (updater instanceof Function) { columnOrder = updater(columnOrder) } else { columnOrder = updater } options.update(old => ({ ...old, state: { ...old.state, columnOrder, }, })) } const setColumnPinning: OnChangeFn<ColumnPinningState> = updater => { if (updater instanceof Function) { columnPinning = updater(columnPinning) } else { columnPinning = updater } options.update(old => ({ ...old, state: { ...old.state, columnPinning, }, })) } const setColumnVisibility: OnChangeFn<VisibilityState> = updater => { if (updater instanceof Function) { columnVisibility = updater(columnVisibility) } else { columnVisibility = updater } options.update(old => ({ ...old, state: { ...old.state, columnVisibility, }, })) } const options = writable<TableOptions<Person>>({ data, columns, state: { columnOrder, columnPinning, columnVisibility, }, onColumnOrderChange: setColumnOrder, onColumnPinningChange: setColumnPinning, onColumnVisibilityChange: setColumnVisibility, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), debugTable: true, }) const randomizeColumns = () => { $table.setColumnOrder(_updater => faker.helpers.shuffle($table.getAllLeafColumns().map(d => d.id)) ) } const regenerate = () => { options.update(options => ({ ...options, data: makeData(5000), })) } const table = createSvelteTable(options) </script> <div class="p-2"> <div class="inline-block border border-black shadow rounded"> <div class="px-1 border-b border-black"> <label> <input checked={$table.getIsAllColumnsVisible()} on:change={e => { console.info($table.getToggleAllColumnsVisibilityHandler()(e)) }} type="checkbox" />{' '} Toggle All </label> </div> {#each $table.getAllLeafColumns() as column} <div class="px-1"> <label> <input checked={column.getIsVisible()} on:change={column.getToggleVisibilityHandler()} type="checkbox" />{' '} {column.id} </label> </div> {/each} </div> <div class="h-4" /> <div class="flex flex-wrap gap-2"> <button on:click={() => regenerate()} class="border p-1"> Regenerate </button> <button on:click={() => randomizeColumns()} class="border p-1"> Shuffle Columns </button> </div> <div class="h-4" /> <div> <label> <input type="checkbox" checked={isSplit} on:change={e => (isSplit = e.currentTarget.checked)} />{' '} Split Mode </label> </div> <div class={`flex ${isSplit ? 'gap-4' : ''}`}> {#if isSplit} <table class="border-2 border-black"> <thead> {#each $table.getLeftHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getCoreRowModel().rows.slice(0, 20) as row} <tr> {#each row.getLeftVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {/if} <table class="border-2 border-black"> <thead> {#each isSplit ? $table.getCenterHeaderGroups() : $table.getHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getCoreRowModel().rows.slice(0, 20) as row} <tr> {#each isSplit ? row.getCenterVisibleCells() : row.getVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {#if isSplit} <table class="border-2 border-black"> <thead> {#each $table.getRightHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getRowModel().rows.slice(0, 20) as row} <tr> {#each row.getRightVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {/if} </div> <pre>{JSON.stringify($table.getState().columnPinning, null, 2)}</pre> </div>
<script lang="ts"> import { writable } from 'svelte/store' import { createSvelteTable, getCoreRowModel, getSortedRowModel, flexRender, } from '@tanstack/svelte-table' import type { ColumnDef, ColumnOrderState, ColumnPinningState, OnChangeFn, TableOptions, VisibilityState, } from '@tanstack/svelte-table' import { makeData, type Person } from './makeData' import { faker } from '@faker-js/faker' import './index.css' const columns: ColumnDef<Person>[] = [ { header: 'Name', footer: props => props.column.id, columns: [ { accessorKey: 'firstName', cell: info => info.getValue(), footer: props => props.column.id, }, { accessorFn: row => row.lastName, id: 'lastName', cell: info => info.getValue(), header: () => 'Last Name', footer: props => props.column.id, }, ], }, { header: 'Info', footer: props => props.column.id, columns: [ { accessorKey: 'age', header: () => 'Age', footer: props => props.column.id, }, { header: 'More Info', columns: [ { accessorKey: 'visits', header: () => 'Visits', footer: props => props.column.id, }, { accessorKey: 'status', header: 'Status', footer: props => props.column.id, }, { accessorKey: 'progress', header: 'Profile Progress', footer: props => props.column.id, }, ], }, ], }, ] const data = makeData(5000) let isSplit = false let columnOrder: ColumnOrderState = [] let columnPinning: ColumnPinningState = {} let columnVisibility: VisibilityState = {} const setColumnOrder: OnChangeFn<ColumnOrderState> = updater => { if (updater instanceof Function) { columnOrder = updater(columnOrder) } else { columnOrder = updater } options.update(old => ({ ...old, state: { ...old.state, columnOrder, }, })) } const setColumnPinning: OnChangeFn<ColumnPinningState> = updater => { if (updater instanceof Function) { columnPinning = updater(columnPinning) } else { columnPinning = updater } options.update(old => ({ ...old, state: { ...old.state, columnPinning, }, })) } const setColumnVisibility: OnChangeFn<VisibilityState> = updater => { if (updater instanceof Function) { columnVisibility = updater(columnVisibility) } else { columnVisibility = updater } options.update(old => ({ ...old, state: { ...old.state, columnVisibility, }, })) } const options = writable<TableOptions<Person>>({ data, columns, state: { columnOrder, columnPinning, columnVisibility, }, onColumnOrderChange: setColumnOrder, onColumnPinningChange: setColumnPinning, onColumnVisibilityChange: setColumnVisibility, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), debugTable: true, }) const randomizeColumns = () => { $table.setColumnOrder(_updater => faker.helpers.shuffle($table.getAllLeafColumns().map(d => d.id)) ) } const regenerate = () => { options.update(options => ({ ...options, data: makeData(5000), })) } const table = createSvelteTable(options) </script> <div class="p-2"> <div class="inline-block border border-black shadow rounded"> <div class="px-1 border-b border-black"> <label> <input checked={$table.getIsAllColumnsVisible()} on:change={e => { console.info($table.getToggleAllColumnsVisibilityHandler()(e)) }} type="checkbox" />{' '} Toggle All </label> </div> {#each $table.getAllLeafColumns() as column} <div class="px-1"> <label> <input checked={column.getIsVisible()} on:change={column.getToggleVisibilityHandler()} type="checkbox" />{' '} {column.id} </label> </div> {/each} </div> <div class="h-4" /> <div class="flex flex-wrap gap-2"> <button on:click={() => regenerate()} class="border p-1"> Regenerate </button> <button on:click={() => randomizeColumns()} class="border p-1"> Shuffle Columns </button> </div> <div class="h-4" /> <div> <label> <input type="checkbox" checked={isSplit} on:change={e => (isSplit = e.currentTarget.checked)} />{' '} Split Mode </label> </div> <div class={`flex ${isSplit ? 'gap-4' : ''}`}> {#if isSplit} <table class="border-2 border-black"> <thead> {#each $table.getLeftHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getCoreRowModel().rows.slice(0, 20) as row} <tr> {#each row.getLeftVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {/if} <table class="border-2 border-black"> <thead> {#each isSplit ? $table.getCenterHeaderGroups() : $table.getHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getCoreRowModel().rows.slice(0, 20) as row} <tr> {#each isSplit ? row.getCenterVisibleCells() : row.getVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {#if isSplit} <table class="border-2 border-black"> <thead> {#each $table.getRightHeaderGroups() as headerGroup} <tr> {#each headerGroup.headers as header} <th colSpan={header.colSpan}> <div class="whitespace-nowrap"> {#if !header.isPlaceholder} <svelte:component this={flexRender( header.column.columnDef.header, header.getContext() )} /> {/if} </div> {#if !header.isPlaceholder && header.column.getCanPin()} <div class="flex gap-1 justify-center"> {#if header.column.getIsPinned() !== 'left'} <button class="border rounded px-2" on:click={() => { header.column.pin('left') }} > {'<='} </button> {/if} {#if header.column.getIsPinned()} <button class="border rounded px-2" on:click={() => { header.column.pin(false) }} > X </button> {/if} {#if header.column.getIsPinned() !== 'right'} <button class="border rounded px-2" on:click={() => { header.column.pin('right') }} > {'=>'} </button> {/if} </div> {/if} </th> {/each} </tr> {/each} </thead> <tbody> {#each $table.getRowModel().rows.slice(0, 20) as row} <tr> {#each row.getRightVisibleCells() as cell} <td> <svelte:component this={flexRender( cell.column.columnDef.cell, cell.getContext() )} /> </td> {/each} </tr> {/each} </tbody> </table> {/if} </div> <pre>{JSON.stringify($table.getState().columnPinning, null, 2)}</pre> </div>
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.