Skip to content

shadcn/ui Integration

Use useTable with shadcn components for a fully styled table that stays in sync with your PHP definitions.

ShadTable Component

tsx
import { useTable } from '@forjedio/inertia-table-react';
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

export default function ShadTable({ tableData, onRowClick, isFetching, isLoading, ...rest }) {
    const { columns, searchTerm, onSearch, onPageChange } = useTable({ tableData, ...rest });
    const hasData = tableData.data.length > 0;

    return (
        <div className="rounded-lg border bg-card text-card-foreground shadow-sm">
            {isLoading && <div className="h-0.5 bg-primary animate-pulse" />}

            {tableData.searchable && (
                <div className="p-4">
                    <Input
                        value={searchTerm}
                        onChange={(e) => onSearch(e.target.value)}
                        placeholder="Search..."
                        className="max-w-sm"
                    />
                </div>
            )}

            <Table>
                <TableHeader>
                    <TableRow>
                        {columns.map((col) => (
                            <TableHead key={col.id}>{col.renderHeader()}</TableHead>
                        ))}
                    </TableRow>
                </TableHeader>
                <TableBody>
                    {hasData ? (
                        tableData.data.map((row, i) => (
                            <TableRow
                                key={row.id}
                                onClick={onRowClick ? () => onRowClick(row) : undefined}
                                className={onRowClick ? 'cursor-pointer' : ''}
                            >
                                {columns.map((col) => (
                                    <TableCell key={col.id}>{col.renderCell(row, i)}</TableCell>
                                ))}
                            </TableRow>
                        ))
                    ) : (
                        <TableRow>
                            <TableCell colSpan={columns.length} className="h-24 text-center text-muted-foreground">
                                No results found.
                            </TableCell>
                        </TableRow>
                    )}
                </TableBody>
            </Table>

            {hasData && (
                <div className="flex items-center justify-between px-4 py-4 border-t">
                    <p className="text-sm text-muted-foreground">
                        Showing <strong>{tableData.meta.from}</strong> to <strong>{tableData.meta.to}</strong>
                        {tableData.meta.total != null && <> of <strong>{tableData.meta.total}</strong> results</>}
                    </p>
                    <div className="flex gap-2">
                        <Button variant="outline" size="sm" disabled={!tableData.links.prev || isFetching}
                            onClick={() => onPageChange(tableData.meta.current_page - 1)}>Previous</Button>
                        <Button variant="outline" size="sm" disabled={!tableData.links.next || isFetching}
                            onClick={() => onPageChange(tableData.meta.current_page + 1)}>Next</Button>
                    </div>
                </div>
            )}
        </div>
    );
}
vue
<!-- Coming soon -->

Usage

tsx
import ShadTable from '@/components/ShadTable';

export default function Servers({ servers }) {
    return <ShadTable tableData={servers} />;
}
vue
<!-- Coming soon -->

The useTable hook handles all logic - search, sort, pagination, column building, display type rendering. The shadcn component only controls markup and styling. When the PHP table definition changes, the frontend adapts automatically.