Veri tablosu
Yönetici panelleri, kontrol panelleri ve sipariş listeleri için sıralanabilir, filtrelenebilir ve sayfalandırılabilir tablolar — neobrütalist tarzda kenarlık ve gölge efektleriyle.
Veri tablosu paketlenmiş bir bileşen değil, bir rehberdir: tablonuzu <Table /> bileşeni ile sıralama, filtreleme, sayfalama ve satır seçimi sağlayan başsız (headless) bir motor olan TanStack Table üzerinden kendiniz kurarsınız — görünümü ise kalın kenarlıklardan, sert gölgelerden ve koyu tipografiden oluşan neobrütalist reçete üstlenir.
Şu durumlarda tercih edin:
- Yönetim panelleri — sıralanabilir sütunlar, filtreler ve satır başına eylem menüleriyle siparişler, kullanıcılar ve faturalar.
- Panolar — biçimlendirilmiş hücreler, durum sütunları ve sayfalanmış API verisiyle ödeme veya etkinlik tabloları.
- Toplu iş akışları — çok sayıda kaydı tek seferde dışa aktarmak, arşivlemek veya silmek için onay kutulu satır seçimi.
Giriş#
Oluşturduğum her veri tablosu veya veri ızgarası benzersiz oldu. Hepsi farklı davranır, belirli sıralama ve filtreleme gereksinimlerine sahiptir ve farklı veri kaynaklarıyla çalışır.
Tüm bu varyasyonları tek bir bileşende birleştirmek mantıklı değil. Bunu yaparsak, headless UI'nin sunduğu esnekliği kaybederiz.
Bu yüzden bir data-table bileşeni yerine, kendinizinkini nasıl oluşturacağınıza dair bir kılavuz sunmanın daha yararlı olacağını düşündüm.
Temel <Table /> bileşeniyle başlayıp sıfırdan karmaşık bir veri tablosu oluşturacağız.
İpucu: Aynı tabloyu uygulamanızda birden fazla yerde kullandığınızı fark ederseniz, onu her zaman yeniden kullanılabilir bir bileşene ayırabilirsiniz.
İçindekiler#
Bu kılavuz, kendi özel veri tablonuzu oluşturmak için TanStack Table ve <Table /> bileşenini nasıl kullanacağınızı gösterecek. Aşağıdaki konuları ele alacağız:
- Temel Tablo
- Satır Eylemleri
- Sayfalama
- Sıralama
- Filtreleme
- Görünürlük
- Satır Seçimi
- Yeniden Kullanılabilir Bileşenler
Kurulum#
<Table />bileşenini projenize ekleyin:
pnpm dlx shadcn@latest add tablenpx shadcn@latest add tableyarn dlx shadcn@latest add tablebunx --bun shadcn@latest add table
tanstack/react-tablebağımlılığını ekleyin:
pnpm add @tanstack/react-tablenpm install @tanstack/react-tableyarn add @tanstack/react-tablebun add @tanstack/react-table
Ön Koşullar#
Son ödemeleri göstermek için bir tablo oluşturacağız. Verilerimiz şöyle görünür:
type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
export const payments: Payment[] = [
{
id: "728ed52f",
amount: 100,
status: "pending",
email: "[email protected]",
},
{
id: "489e1d42",
amount: 125,
status: "processing",
email: "[email protected]",
},
// ...
]Proje Yapısı#
Aşağıdaki dosya yapısını oluşturarak başlayın:
app
└── payments
├── columns.tsx
├── data-table.tsx
└── page.tsxBurada bir Next.js örneği kullanıyorum ancak bu, diğer herhangi bir React framework'ü için de çalışır.
columns.tsx(istemci bileşeni), sütun tanımlarımızı içerecek.data-table.tsx(istemci bileşeni),<DataTable />bileşenimizi içerecek.page.tsx(sunucu bileşeni), verileri getirip tablomuzu render edeceğimiz yerdir.
Temel Tablo#
Temel bir tablo oluşturarak başlayalım.
Sütun Tanımları#
Öncelikle sütunlarımızı tanımlayacağız.
"use client"
import { ColumnDef } from "@tanstack/react-table"
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: "status",
header: "Status",
},
{
accessorKey: "email",
header: "Email",
},
{
accessorKey: "amount",
header: "Amount",
},
]Not: Sütunlar, tablonuzun nasıl görüneceğinin özünü tanımladığınız yerdir. Görüntülenecek verileri ve bunların nasıl biçimlendirileceğini, sıralanacağını ve filtreleneceğini belirler.
<DataTable /> bileşeni#
Ardından, tablomuzu render etmek için bir <DataTable /> bileşeni oluşturacağız.
"use client"
import {
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
}
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
})
return (
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}İpucu: <DataTable />'ı birden fazla yerde kullandığınızı fark ederseniz, bu, onu components/ui/data-table.tsx'e ayırarak yeniden kullanılabilir hale getirebileceğiniz bileşendir.
<DataTable columns={columns} data={data} />
Tabloyu render etme#
Son olarak, tablomuzu sayfa bileşenimizde render edeceğiz.
import { columns, Payment } from "./columns"
import { DataTable } from "./data-table"
async function getData(): Promise<Payment[]> {
// Fetch data from your API here.
return [
{
id: "728ed52f",
amount: 100,
status: "pending",
email: "[email protected]",
},
// ...
]
}
export default async function DemoPage() {
const data = await getData()
return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={data} />
</div>
)
}Hücre Biçimlendirme#
Dolar tutarını göstermek için tutar hücresini biçimlendirelim. Ayrıca hücreyi sağa hizalayacağız.
Sütun tanımını güncelleme#
Tutar için header ve cell tanımlarını aşağıdaki gibi güncelleyin:
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: "amount",
header: () => <div className="text-right">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount)
return <div className="text-right font-medium">{formatted}</div>
},
},
]Diğer hücreleri ve başlıkları biçimlendirmek için aynı yaklaşımı kullanabilirsiniz.
Satır Eylemleri#
Tablomuza satır eylemleri ekleyelim. Bunun için bir <DropdownMenu /> bileşeni kullanacağız.
Sütun tanımını güncelleme#
Yeni bir actions sütunu eklemek için sütun tanımımızı güncelleyin. actions hücresi bir <DropdownMenu /> bileşeni döndürür.
"use client"
import { ColumnDef } from "@tanstack/react-table"
import { MoreHorizontal } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export const columns: ColumnDef<Payment>[] = [
// ...
{
id: "actions",
cell: ({ row }) => {
const payment = row.original
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => navigator.clipboard.writeText(payment.id)}
>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
},
},
// ...
]cell fonksiyonunda row.original kullanarak satır verilerine erişebilirsiniz. Bunu satırınıza yönelik eylemleri işlemek için kullanın; örneğin API'nize bir DELETE çağrısı yapmak için id'yi kullanın.
Sayfalama#
Ardından, tablomuza sayfalama ekleyeceğiz.
<DataTable> güncelleme#
import {
ColumnDef,
flexRender,
getCoreRowModel,
getPaginationRowModel,
useReactTable,
} from "@tanstack/react-table"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
// ...
}Bu, satırlarınızı otomatik olarak 10'arlı sayfalara böler. Sayfa boyutunu özelleştirme ve manuel sayfalama uygulama hakkında daha fazla bilgi için sayfalama belgelerine bakın.
Sayfalama denetimleri ekleme#
<Button /> bileşenini ve table.previousPage(), table.nextPage() API metotlarını kullanarak tablomuza sayfalama denetimleri ekleyebiliriz.
import { Button } from "@/components/ui/button"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table>
{ // .... }
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
)
}Daha gelişmiş bir sayfalama bileşeni için Yeniden Kullanılabilir Bileşenler bölümüne bakın.
Sıralama#
E-posta sütununu sıralanabilir yapalım.
<DataTable> güncelleme#
"use client"
import * as React from "react"
import {
ColumnDef,
SortingState,
flexRender,
getCoreRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}Başlık hücresini sıralanabilir yapma#
Şimdi sıralama denetimleri eklemek için email başlık hücresini güncelleyebiliriz.
"use client"
import { ColumnDef } from "@tanstack/react-table"
import { ArrowUpDown } from "lucide-react"
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: "email",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Email
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
},
]Bu, kullanıcı başlık hücresine tıkladığında tabloyu otomatik olarak sıralar (artan ve azalan).
Filtreleme#
Tablomuzdaki e-postaları filtrelemek için bir arama girişi ekleyelim.
<DataTable> güncelleme#
"use client"
import * as React from "react"
import {
ColumnDef,
ColumnFiltersState,
SortingState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
onColumnFiltersChange: setColumnFilters,
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
columnFilters,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
</div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}Filtreleme artık email sütunu için etkinleştirildi. Diğer sütunlara da filtreler ekleyebilirsiniz. Filtreleri özelleştirme hakkında daha fazla bilgi için filtreleme belgelerine bakın.
Görünürlük#
Sütun görünürlüğü eklemek, @tanstack/react-table görünürlük API'si kullanılarak oldukça basittir.
<DataTable> güncelleme#
"use client"
import * as React from "react"
import {
ColumnDef,
ColumnFiltersState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnFilters,
columnVisibility,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={table.getColumn("email")?.getFilterValue() as string}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto">
Columns
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter(
(column) => column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}Bu, sütun görünürlüğünü açıp kapatmak için kullanabileceğiniz bir açılır menü ekler.
Satır Seçimi#
Ardından, tablomuza satır seçimi ekleyeceğiz.
Sütun tanımlarını güncelleme#
"use client"
import { ColumnDef } from "@tanstack/react-table"
import { Badge } from "@/components/ui/badge"
import { Checkbox } from "@/components/ui/checkbox"
export const columns: ColumnDef<Payment>[] = [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
]<DataTable> güncelleme#
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table />
</div>
</div>
)
}Bu, her satıra bir onay kutusu ve tüm satırları seçmek için başlığa bir onay kutusu ekler.
Seçili satırları gösterme#
table.getFilteredSelectedRowModel() API'sini kullanarak seçili satır sayısını gösterebilirsiniz.
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>Yeniden Kullanılabilir Bileşenler#
İşte veri tablolarınızı oluşturmak için kullanabileceğiniz bazı bileşenler. Bunlar Tasks demosundandır.
Sütun başlığı#
Herhangi bir sütun başlığını sıralanabilir ve gizlenebilir yapın.
import { type Column } from "@tanstack/react-table"
import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/base/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/base/ui/dropdown-menu"
interface DataTableColumnHeaderProps<
TData,
TValue,
> extends React.HTMLAttributes<HTMLDivElement> {
column: Column<TData, TValue>
title: string
}
export function DataTableColumnHeader<TData, TValue>({
column,
title,
className,
}: DataTableColumnHeaderProps<TData, TValue>) {
if (!column.getCanSort()) {
return <div className={cn(className)}>{title}</div>
}
return (
<div className={cn("flex items-center gap-2", className)}>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
variant="ghost"
size="sm"
className="-ml-3 h-8 data-popup-open:bg-accent"
/>
}
>
<span>{title}</span>
{column.getIsSorted() === "desc" ? (
<ArrowDown />
) : column.getIsSorted() === "asc" ? (
<ArrowUp />
) : (
<ChevronsUpDown />
)}
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => column.toggleSorting(false)}>
<ArrowUp />
Asc
</DropdownMenuItem>
<DropdownMenuItem onClick={() => column.toggleSorting(true)}>
<ArrowDown />
Desc
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
<EyeOff />
Hide
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
)
}
export const columns = [
{
accessorKey: "email",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Email" />
),
},
]Sayfalama#
Sayfa boyutu ve seçim sayısı dahil olmak üzere tablonuza sayfalama denetimleri ekleyin.
import { type Table } from "@tanstack/react-table"
import {
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
} from "lucide-react"
import { Button } from "@/registry/base/ui/button"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/base/ui/select"
const pageSizeItems = [10, 20, 25, 30, 40, 50].map((pageSize) => ({
label: `${pageSize}`,
value: `${pageSize}`,
}))
interface DataTablePaginationProps<TData> {
table: Table<TData>
}
export function DataTablePagination<TData>({
table,
}: DataTablePaginationProps<TData>) {
return (
<div className="flex items-center justify-between px-2">
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex items-center space-x-6 lg:space-x-8">
<div className="flex items-center space-x-2">
<p className="text-sm font-medium">Rows per page</p>
<Select
items={pageSizeItems}
value={`${table.getState().pagination.pageSize}`}
onValueChange={(value) => {
if (value !== null) {
table.setPageSize(Number(value))
}
}}
>
<SelectTrigger className="h-8 w-[70px]">
<SelectValue />
</SelectTrigger>
<SelectContent side="top">
{pageSizeItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
Page {table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</div>
<div className="flex items-center space-x-2">
<Button
variant="outline"
size="icon"
className="hidden size-8 lg:flex"
onClick={() => table.setPageIndex(0)}
disabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to first page</span>
<ChevronsLeft />
</Button>
<Button
variant="outline"
size="icon"
className="size-8"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to previous page</span>
<ChevronLeft />
</Button>
<Button
variant="outline"
size="icon"
className="size-8"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to next page</span>
<ChevronRight />
</Button>
<Button
variant="outline"
size="icon"
className="hidden size-8 lg:flex"
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
disabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to last page</span>
<ChevronsRight />
</Button>
</div>
</div>
</div>
)
}
<DataTablePagination table={table} />Sütun değiştirme#
Sütun görünürlüğünü açıp kapatmak için bir bileşen.
"use client"
import { type Table } from "@tanstack/react-table"
import { Settings2 } from "lucide-react"
import { Button } from "@/registry/base/ui/button"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/base/ui/dropdown-menu"
export function DataTableViewOptions<TData>({
table,
}: {
table: Table<TData>
}) {
return (
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
variant="outline"
size="sm"
className="ml-auto hidden h-8 lg:flex"
/>
}
>
<Settings2 />
View
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[150px]">
{/* GroupLabel (Base UI) needs a Group ancestor or it throws error #31. */}
<DropdownMenuGroup>
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
</DropdownMenuGroup>
<DropdownMenuSeparator />
{table
.getAllColumns()
.filter(
(column) =>
typeof column.accessorFn !== "undefined" && column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
)
}
<DataTableViewOptions table={table} />RTL#
Neobrutalism'de RTL desteğini etkinleştirmek için RTL yapılandırma kılavuzuna bakın.
Erişilebilirlik#
TanStack Table başsızdır — hiçbir işaretleme üretmez; erişilebilirlik bu rehberdeki öğelerden gelir. <Table /> bileşeni doğal <table>, <th> ve <td> öğeleri üretir; bunlar WAI-ARIA Table deseni uyarınca ekran okuyuculara satır ve sütun bağlamı sağlar. Kurarken iki noktaya dikkat edin: o an sıralanan üstbilgiye aria-sort verin; seçim onay kutularındaki aria-label'ı ve yalnızca simgeden oluşan tetikleyicilerdeki sr-only metnini koruyun (yukarıdaki kod parçaları ikisini de yapar).
Bu rehberdeki her denetim doğal bir düğme, onay kutusu ya da giriştir; dolayısıyla klavye davranışı tarayıcı varsayılanıdır:
| Tuş | Eylem |
|---|---|
Tab / Shift + Tab | Odağı tablonun denetimleri arasında gezdirir — filtre girişi, sıralama üstbilgileri, satır menüleri, sayfalama |
Space / Enter | Odaklanılan sıralama veya sayfalama düğmesini etkinleştirir |
Space | Odaklanılan satır veya tümünü-seç onay kutusunu değiştirir |