Column Visibility Example
A toolbar reads columns$ and columnVisibilityState$ through an engineRef and publishes setColumnVisibility$ and resetColumnVisibility$. The internalId column starts hidden via visible={false} and can be toggled back on from the toolbar.
APIs used
Section titled “APIs used”columns$— column declarations from the enginecolumnVisibilityState$— current visibility overridessetColumnVisibility$/resetColumnVisibility$— toggle and reset
import { Button } from '@/components/ui/button'
import { DataTable, DataTableCell, DataTableColumn, DataTableColumnHeader } from '@/components/ui/data-table'
import { localModel, columns$, useEngineRef, useRemoteCellValue, useRemotePublisher } from '@virtuoso.dev/data-table'
import { columnVisibilityState$, resetColumnVisibility$, setColumnVisibility$ } from '@virtuoso.dev/data-table/column-visibility'
import { products } from './data'
const model = localModel({ data: products })
export default function App() {
const engineRef = useEngineRef()
const columns = useRemoteCellValue(columns$, engineRef)
const visibility = useRemoteCellValue(columnVisibilityState$, engineRef)
const setColumnVisibility = useRemotePublisher(setColumnVisibility$, engineRef)
const resetColumnVisibility = useRemotePublisher(resetColumnVisibility$, engineRef)
return (
<div className="space-y-4">
<div className="flex flex-wrap gap-2">
{[...(columns ?? new Map())].map(([key, column]) => {
const visible = visibility?.get(key) ?? column.visible !== false
return (
<Button key={key} onClick={() => setColumnVisibility({ key, visible: !visible })} variant={visible ? 'secondary' : 'outline'}>
{visible ? 'Hide' : 'Show'} {column.field}
</Button>
)
})}
<Button onClick={() => resetColumnVisibility()} variant="outline">
Reset
</Button>
</div>
<DataTable className="rounded-xl" model={model} engineRef={engineRef} style={{ height: 400 }}>
<DataTableColumn field="name">
<DataTableColumnHeader>Product</DataTableColumnHeader>
<DataTableCell className="font-medium">{({ row }) => row.data.name}</DataTableCell>
</DataTableColumn>
<DataTableColumn field="category">
<DataTableColumnHeader>Category</DataTableColumnHeader>
<DataTableCell>{({ cellValue }) => String(cellValue)}</DataTableCell>
</DataTableColumn>
<DataTableColumn field="status">
<DataTableColumnHeader>Status</DataTableColumnHeader>
<DataTableCell>{({ cellValue }) => String(cellValue)}</DataTableCell>
</DataTableColumn>
<DataTableColumn field="region">
<DataTableColumnHeader>Region</DataTableColumnHeader>
<DataTableCell>{({ cellValue }) => String(cellValue)}</DataTableCell>
</DataTableColumn>
<DataTableColumn field="internalId" visible={false}>
<DataTableColumnHeader>Internal ID</DataTableColumnHeader>
<DataTableCell>{({ cellValue }) => String(cellValue)}</DataTableCell>
</DataTableColumn>
</DataTable>
</div>
)
}Persisted visibility is keyed by field, not by the generated runtime column key. Renaming a field invalidates its saved visibility — see Field names are the persistence contract for the migration rule.