Search Table
Add global search functionality to quickly find data across all columns.
Preview with Controlled State
View Full State Object
{
"isLoading": true,
"dataLength": 0
}""
[]
{
"pageIndex": 0,
"pageSize": 5
}{}Introduction
Section titled “Introduction”The Search Table adds a global search input that filters data across all columns. Users can quickly find what they’re looking for without complex filters.
Installation
Section titled “Installation”Install the DataTable core and add-ons for this example:
First time using
@niko-table? See the Installation Guide to set up the registry.
For other add-ons or manual copy-paste, see the Installation Guide.
Prerequisites
Section titled “Prerequisites”We are going to build a table to show customers. Here’s what our data looks like:
type Customer = { id: string name: string email: string company: string phone: string}
const data: Customer[] = [ { id: "1", name: "John Doe", company: "Acme Corp", phone: "+1 234-567-8900", }, // ...]Basic Table with Search
Section titled “Basic Table with Search”Let’s start by building a table with global search.
Column Definitions
Section titled “Column Definitions”First, we’ll define our columns.
"use client"
import { DataTableColumnHeader } from "@/components/niko-table/components/data-table-column-header"import { DataTableColumnTitle } from "@/components/niko-table/components/data-table-column-title"import { DataTableColumnSortMenu } from "@/components/niko-table/components/data-table-column-sort"import type { DataTableColumnDef } from "@/components/niko-table/types"
export type Customer = { id: string name: string email: string company: string phone: string}
export const columns: DataTableColumnDef<Customer>[] = [ { accessorKey: "name", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Name" }, }, { accessorKey: "email", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Email" }, }, { accessorKey: "company", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Company" }, }, { accessorKey: "phone", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Phone" }, },]<DataTable /> component
Section titled “<DataTable /> component”Next, we’ll add the search filter component.
"use client"
import { DataTableRoot } from "@/components/niko-table/core/data-table-root"import { DataTable } from "@/components/niko-table/core/data-table"import { DataTableHeader, DataTableBody,} from "@/components/niko-table/core/data-table-structure"import { DataTableToolbarSection } from "@/components/niko-table/components/data-table-toolbar-section"import { DataTablePagination } from "@/components/niko-table/components/data-table-pagination"import { DataTableSearchFilter } from "@/components/niko-table/components/data-table-search-filter"import { DataTableColumnHeader } from "@/components/niko-table/components/data-table-column-header"import { DataTableColumnTitle } from "@/components/niko-table/components/data-table-column-title"import { DataTableColumnSortMenu } from "@/components/niko-table/components/data-table-column-sort"import type { DataTableColumnDef } from "@/components/niko-table/types"
type Customer = { id: string name: string email: string company: string phone: string}
const columns: DataTableColumnDef<Customer>[] = [ { accessorKey: "name", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Name" }, }, { accessorKey: "email", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Email" }, }, { accessorKey: "company", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Company" }, }, { accessorKey: "phone", header: () => ( <DataTableColumnHeader> <DataTableColumnTitle /> <DataTableColumnSortMenu /> </DataTableColumnHeader> ), meta: { label: "Phone" }, },]
export function SearchTable({ data }: { data: Customer[] }) { return ( <DataTableRoot data={data} columns={columns} config={{ enablePagination: true, enableSorting: true, enableFilters: true, initialPageSize: 10, }} > <DataTableToolbarSection> <DataTableSearchFilter placeholder="Search customers..." /> </DataTableToolbarSection>
<DataTable> <DataTableHeader /> <DataTableBody /> </DataTable>
<DataTablePagination /> </DataTableRoot> )}How Search Works
Section titled “How Search Works”The global search filter works by:
- Converting all searchable column values to strings
- Searching for the query across all columns
- Returning rows where ANY column matches
- Case-insensitive matching by default
Controlling Searchable Columns
Section titled “Controlling Searchable Columns”By default, all columns are searchable. To exclude columns:
{ accessorKey: "id", header: "ID", enableColumnFilter: false, // Not searchable}Controlled Search State
Section titled “Controlled Search State”Manage search state externally:
import { useState } from "react"
export function ControlledSearchTable({ data }: { data: Customer[] }) { const [searchValue, setSearchValue] = useState("")
return ( <DataTableRoot data={data} columns={columns} config={{ enableFilters: true, }} onGlobalFilterChange={setSearchValue} > <DataTableToolbarSection> <DataTableSearchFilter placeholder="Search customers..." value={searchValue} onChange={setSearchValue} /> </DataTableToolbarSection>
<DataTable> <DataTableHeader /> <DataTableBody /> </DataTable>
<DataTablePagination /> </DataTableRoot> )}Custom Search Input
Section titled “Custom Search Input”Build your own search UI using the context:
import { useDataTable } from "@/components/niko-table/core/data-table-context"import { Input } from "@/components/ui/input"import { Search, X } from "lucide-react"import { Button } from "@/components/ui/button"
function CustomSearchInput() { const { table } = useDataTable<Customer>() const globalFilter = table.getState().globalFilter
return ( <div className="relative"> <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" /> <Input value={(globalFilter as string) ?? ""} onChange={e => table.setGlobalFilter(e.target.value)} placeholder="Search..." className="pr-9 pl-9" /> {globalFilter && ( <Button variant="ghost" size="sm" className="absolute top-1/2 right-1 h-7 w-7 -translate-y-1/2 p-0" onClick={() => table.setGlobalFilter("")} > <X className="h-4 w-4" /> </Button> )} </div> )}When to Use
Section titled “When to Use”✅ Use Search Table when:
- Users need quick, simple searching
- Data is text-heavy (names, descriptions, etc.)
- You want a clean, minimal UI
- Dataset is < 1000 rows (client-side)
❌ Consider other options when:
- You need column-specific filters (use Advanced Table)
- Dataset is > 1000 rows (implement server-side filtering)
- Search is not the primary use case (use Basic Table)
Next Steps
Section titled “Next Steps”- Advanced Table - Add advanced filtering and sorting menus