Tech TutorBangla Web Documentation
Portfolio
HomeHTMLCSSTailwind CSSJavaScriptTypeScriptReactNext.jsNode.jsExpressSocket.IOExpoWordPressPostgreSQLPrismaPostgresNestJSMongoDBDockerTanStackTanStack TableRTK QueryGitGitHub
  • TanStack Table Documentation12টি অধ্যায়
প্রযুক্তি নির্বাচন
HomeHTMLCSSTailwind CSSJavaScriptTypeScriptReactNext.jsNode.jsExpressSocket.IOExpoWordPressPostgreSQLPrismaPostgresNestJSMongoDBDockerTanStackTanStack TableRTK QueryGitGitHub
  • Introduction
  • Installation & Setup
  • Core Concepts
  • Column Definitions
  • Row Models
  • Sorting
  • Filtering
  • Pagination
  • Row Selection
  • Column Management
  • Server-side Mode
  • Advanced Features
  1. Docs
  2. TanStack Table
  3. Filtering — খোঁজা ও ছাঁকা
TanStack TableIntermediate

Filtering — খোঁজা ও ছাঁকা

globalFilter বনাম columnFilters, filterFns, custom filter function, debounced search, filter UI, manualFiltering — বাংলায়।

43টি অংশবাংলা ভাষায়

সাজানোর পর এলো খোঁজা। TanStack-এ filtering-এর দুটি স্তর আছে — global filter (পুরো টেবিলে একসাথে) আর column filter (নির্দিষ্ট কলামে)। দুটো একসাথেও চলতে পারে।

দুই স্তর

// ১. global filter — একটা সার্চ বক্স, সব কলামে মিলে
const [globalFilter, setGlobalFilter] = useState("");

// ২. column filter — প্রতিটি কলামে আলাদা শর্ত
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);

const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
  getFilteredRowModel: getFilteredRowModel(), // ← এটা ছাড়া হবে না
  state: { globalFilter, columnFilters },
  onGlobalFilterChange: setGlobalFilter,
  onColumnFiltersChange: setColumnFilters,
});
global filtercolumn filter
stateglobalFilter: stringcolumnFilters: { id, value }[]
UIএকটা search inputকলামভিত্তিক dropdown/range
filterFnsglobalFilterFnপ্রতিটি filterFns-এর নিজস্ব
কোন কলামে মিলবেenableGlobalFilter: true সবগুলোশুধু ওই কলাম

দুটো একসাথে চালু থাকলে AND হয় — মানে global-এ "টি" আর category-তে "books" — দুটোই মেলে এমন row বাকি থাকে।

Global filter — search box

global-filter.tsxtsx
tsx
export function GlobalFilter({
  table,
}: {
  table: Table<Product>;
}) {
  const value = table.getState().globalFilter ?? "";

  return (
    <div className="relative max-w-sm">
      <Search className="absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
      <Input
        value={value}
        onChange={(e) => table.setGlobalFilter(e.target.value)}
        placeholder="পণ্য খুঁজুন…"
        className="pl-9"
      />
    </div>
  );
}

table.setGlobalFilter() লিখলে onGlobalFilterChange চলে, তাই ওই state-ও বদলায়। অর্থাৎ দুটো একসাথে ব্যবহার করা যায় — নিজের setGlobalFilter বা table-এর method, যেটা আপনার পছন্দ।

কোন কলামে মিলবে

{
  accessorKey: "createdAt",
  enableGlobalFilter: false,   // ISO date সার্চে শুধু ধুলো মিলবে
},
{
  accessorKey: "isActive",
  enableGlobalFilter: false,   // boolean — অর্থহীন
},
{
  accessorKey: "name",
  enableGlobalFilter: true,    // ডিফল্ট
},
{
  id: "searchText",
  accessorFn: (row) =>
    `${row.name} ${row.category} ${row.id}`.toLowerCase(),
  enableGlobalFilter: true,
}

accessorKey: "name" দিলে global search শুধু নামে মেলে। চাইলে একাধিক কলামে একসাথে মেলাতে একটা সাহায্যকারী কলাম বানান যেটা enableHiding: false — দেখা যাবে না, কিন্তু search-এ কাজ করবে।

বাংলায় সার্চ ঠিক করা

useReactTable({
  getFilteredRowModel: getFilteredRowModel(),
  globalFilterFn: "includesString",
  // বাংলা সম্পূর্ণ সংযুক্তাক্ষরে লেখা হয় — একটু সহজ করে দিই
  globalFilterFn: (row, columnId, filterValue) => {
    const cell = row.getValue(columnId);
    if (cell == null) return false;
    return String(cell)
      .normalize("NFC")
      .toLowerCase()
      .includes(String(filterValue).normalize("NFC").toLowerCase());
  },
})

Column filters

import type { ColumnFiltersState } from "@tanstack/react-table";

// বর্তমান অবস্থা
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);

// [
//   { id: "category", value: "books" },
//   { id: "stock", value: [10, 50] },     // range
//   { id: "name", value: "react" },
// ]

// কোনো কলামের filter বদলানো
table.getColumn("category")?.setFilterValue("books");

// সব filter মুছে ফেলা
table.resetColumnFilters();

// একটি column-এর মান পড়া
table.getColumn("category")?.getFilterValue();

কোন কলামে কী ধরনের filter

{
  accessorKey: "category",
  filterFn: "equalsString",      // নির্দিষ্ট একটি মান
},
{
  accessorKey: "name",
  filterFn: "includesString",    // অংশ মিললেই হবে
},
{
  accessorKey: "price",
  filterFn: "inNumberRange",     // [min, max]
},
{
  accessorKey: "rating",
  filterFn: "inNumberRange",
},
{
  accessorKey: "isActive",
  filterFn: "equalsBoolean",
},
{
  id: "multi",
  filterFn: (row, columnId, filterValue: string[]) =>
    filterValue.includes(row.getValue(columnId)),
}

Built-in filterFns

filterFnতুলনাউদাহরণ value
equalsStringহুবহু সমান"books"
equalsNumberসংখ্যা সমান0
equalsBooleantrue/falsetrue
arrayIncludesStringarray-তে আছে কিনা["a","b"]
arrIncludesSomearray-র কোনো একটা মিলে["a","b"]
inNumberRangemin ≤ মান ≤ max[10, 100]
inStringRangelexically মধ্যে["a", "m"]
includesStringঅংশ মিললেই"rea"
includesStringWithOpposites!rea → যেসব মিলে না"!rea"
includesNumberঅংশ সংখ্যা"1"

includesString default — মানে "a" লিখলে "Book"-এও মিলবে। এটা অনেকে খারাপ লাগে। চাইলে শুধু শুরুর দিকে মিল করাতে filterFn: "startsWith" লিখে custom বানাতে পারেন।

Custom filter function

import type { FilterFn } from "@tanstack/react-table";

// বাংলায় খোঁজা
const searchBangla: FilterFn<any> = (row, columnId, filterValue) => {
  const value = String(filterValue ?? "").trim();
  if (!value) return true; // ফাঁকা হলে সব থাকবে

  const cell = String(row.getValue(columnId) ?? "")
    .normalize("NFC")
    .toLowerCase();
  const needle = value.normalize("NFC").toLowerCase();

  return cell.includes(needle);
};

// price: সবচেয়ে সস্তা আগে, বাকি বাদ
const priceAsc: FilterFn<number> = (row, columnId, filterValue: number) =>
  row.getValue<number>(columnId) === filterValue;

// ব্যবহার
{
  accessorKey: "name",
  filterFn: searchBangla,
}

Filter UI — category dropdown

category-filter.tsxtsx
tsx
export function CategoryFilter({
  table,
}: {
  table: Table<Product>;
}) {
  const column = table.getColumn("category");
  const value = column?.getFilterValue() as string | undefined;

  // faceted values — ডেটা থেকেই অপশন বের হবে
  const options = column?.getFacetedUniqueValues() ?? new Map();

  return (
    <Select
      value={value ?? "all"}
      onValueChange={(v) =>
        column?.setFilterValue(v === "all" ? undefined : v)
      }
    >
      <SelectTrigger className="w-40">
        <SelectValue placeholder="ক্যাটাগরি" />
      </SelectTrigger>
      <SelectContent>
        <SelectItem value="all">সব</SelectItem>
        {[...options.keys()].map((option) => (
          <SelectItem key={option} value={String(option)}>
            {option} ({options.get(option)})
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}

getFacetedUniqueValues() সাধারণ ডেটায় কাজ করে (faceted row model চালু থাকলে)। Server-side mode-এ এটা ফাঁকা ফেরত দেয় — তখন অপশন আলাদা endpoint থেকে আনতে হয়, কারণ table-এর কাছে মোট ডেটাই নেই।

Price range filter

export function PriceFilter({ table }: { table: Table<Product> }) {
  const column = table.getColumn("price");
  const range = (column?.getFilterValue() as [number, number]) ?? [0, 200000];

  return (
    <div className="flex items-center gap-2">
      <Input
        type="number"
        value={range[0]}
        onChange={(e) =>
          column?.setFilterValue([
            Number(e.target.value),
            range[1],
          ])
        }
        className="w-28"
      />
      <span className="text-muted-foreground">—</span>
      <Input
        type="number"
        value={range[1]}
        onChange={(e) =>
          column?.setFilterValue([
            range[0],
            Number(e.target.value),
          ])
        }
        className="w-28"
      />
    </div>
  );
}

ফলাফল দেখানো ও মুছে ফেলা

const filteredCount = table.getFilteredRowModel().rows.length;
const totalCount = table.getCoreRowModel().rows.length;
const hasFilter = table.getState().globalFilter || table.getState().columnFilters.length > 0;

// UI
<footer className="border-t p-3 text-sm text-muted-foreground">
  {hasFilter ? (
    <div className="flex items-center gap-2">
      <span>
        {filteredCount}টির মধ্যে {filteredCount}টি পাওয়া গেছে
      </span>
      <Button
        variant="ghost"
        size="sm"
        onClick={() => {
          table.setGlobalFilter("");
          table.resetColumnFilters();
        }}
      >
        filter মুছুন
      </Button>
    </div>
  ) : (
    <span>মোট {totalCount}টি পণ্য</span>
  )}
</footer>

Debounced search

প্রতিটি keystroke-এ filter চললে বড় ডেটায় lag পড়ে। ছোট টেবিলে দরকার নেই, বড় অ্যাপে debounce করুন।

import { useDeferredValue } from "react"; // React 19-এর সহজ সমাধান

export function DataTable({ data, columns }: DataTableProps) {
  const [input, setInput] = useState("");
  const deferredInput = useDeferredValue(input);

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    state: { globalFilter: deferredInput },
    onGlobalFilterChange: setInput,
  });

  // input = তাৎক্ষণিক (টাইপ করলেই দেখাবে)
  // globalFilter = পিছনে (হিসাব ধীর, ফলাফল একটু পরে আসে)
}
// বাইরের লাইব্রেরি ব্যবহার করতে চাইলে
import { useDebounce } from "use-debounce";

const [input, setInput] = useState("");
const [debounced] = useDebounce(input, 300);

// globalFilter: debounced, onGlobalFilterChange: setInput

manualFiltering

Server-এ filter হলে table কে বলে দিতে হয় যে সে নিজে filter করবে না — manualFiltering: true। তখন getFilteredRowModel()-এর ফলাখানা data-র সমান, কারণ transform-ই হয়নি।

useReactTable({
  data: data?.items ?? [],
  getCoreRowModel: getCoreRowModel(),
  manualFiltering: true,   // filter API-তে যাচ্ছে
})
ফাঁকা ফলাফল বনাম loading

Server mode-এ getIsAllRowsFiltered() সবসময় false — কারণ table জানে না মোট কতটা ছিল। ফলে "কোনো ফলাফল নেই" আর "লোড হচ্ছে" গুলিয়ে যেতে পারে। isPending আর rows.length === 0 — দুটো আলাদা করে যাচাই করুন।

সাধারণ বাগ

ঘটনাকারণসমাধান
filter কাজ করে নাgetFilteredRowModel() নেইযোগ করুন
সব কলামে মেলে নাenableGlobalFilter: falseযেটায় খুঁজছেন সেটা true করুন
ISO date সার্চে ধুলো মিলেdefault global filterenableGlobalFilter: false
খালি box-এ সব row চলে যায়""-এর জন্য guard নেইcustom filter-এ if (!value) return true
reset হলে state-এ পুরোনো মানresetColumnFilters vs setFilterValue(undefined)সব ক্ষেত্রে resetColumnFilters()
filter বদলালে খালি পেজautoResetPageIndex বন্ধঅধ্যায় ৮ দেখুন
number range কাজ করে নাinNumberRange বসানো হয়নিfilterFn: "inNumberRange"

সারসংক্ষেপ

  • getFilteredRowModel() ছাড়া filtering হবে না
  • global = একটা সার্চ বক্স; column = কলামভিত্তিক শর্ত
  • filterFn না দিলে includesString — শুধু নাম খুঁজলে startsWith ভাবুন
  • বড় ডেটায় useDeferredValue বা debounce
  • server-এ filter = manualFiltering: true + getFilteredRowModel() বাদ

পরবর্তী

Filtering শেষ। পরের অধ্যায়ে pagination — pageIndex-এর শূন্য-ভিত্তিক গণনা, rowCount, আর সবচেয়ে বেশি ভুল হওয়া off-by-one সমস্যাটা।

শেষ প্যারায় নিজে practice করুন — কোড কপি করে নিজের এডিটরে চালিয়ে দেখুন।
আগেরSorting — সাজানোপরেরPagination — পেজ ভাগ
এই পেজে
Tech Tutor

বাংলায় ওয়েব ডেভেলপমেন্ট ডকুমেন্টেশন শিখুন — ধাপে ধাপে।

Homeসব ডকুমেন্টেশনQuick Startআমার নোটস

© 2026 Tech Tutor. বাংলায় শিখুন, বাংলায় গড়ুন।

mdanamolhasan1998@gmail.com