The DataTb component provides a powerful, flexible way to display tabular data from various sources with built-in sorting, filtering, and pagination. Built on React and TanStack Table.
Live Examples
Minimal example
Load data from a CSV file with automatic column detection:
<DataTb csv="/data/ksa.csv" searchable pagination client:load/>CSV with Custom Columns
Same data with customized column display and formatting:
<DataTb csv="/data/ksa.csv" columns={[ { key: 'Item_Label', header: 'Site ID', sortable: true }, { key: 'Name', header: 'Name', sortable: true }, { key: 'Site_Name', header: 'Site Name' }, { key: 'Survey_Year', header: 'Survey Year', format: 'number' }, { key: 'Subregion', header: 'Subregion' } ]} searchable pagination={{ pageSize: 5, showPageSize: true }} initialSort={{ columnKey: 'Item_Label', direction: 'asc' }} client:load/>Inline JSON Data
Display data directly from JSON:
export const jsonData = [ { language: 'JavaScript', year: 1995, creator: 'Brendan Eich' }, { language: 'Python', year: 1991, creator: 'Guido van Rossum' }, { language: 'Java', year: 1995, creator: 'James Gosling' }, { language: 'TypeScript', year: 2012, creator: 'Anders Hejlsberg' }, { language: 'Rust', year: 2010, creator: 'Graydon Hoare' }];
<DataTb json={jsonData} searchable pagination={false} client:load/>API with Transformer
Fetch data from a public API and transform it:
<DataTb api="https://jsonplaceholder.typicode.com/todos" columns={[ { key: 'title', header: 'Title', sortable: true }, { key: 'userId', header: 'User ID' }, { key: 'completed', header: 'Status', labels: { 'true': '✅ Done', 'false': '⏳ Pending' } } ]} searchable pagination={{ pageSize: 10 }} client:load/>Directus Integration
Load data from a Directus collection using the simplified interface.
Note: This example requires PUBLIC_DIRECTUS_URL and PUBLIC_DIRECTUS_TOKEN environment variables in your .env file
<DataTb directus={{ table: "scms_ksa", queryString: "limit=-1&offset=0", }} searchable pagination client:load/>Complex Transformations (The Wrapper Pattern)
Question: “Can I use functions for complex transformations?”
Answer: Not directly inside MDX props (due to serialization limits), but YES by using a Wrapper Component.
Create a React component (AdvancedTable.tsx) that defines your columns with functions, and import it here.
export default function AdvancedTable() { const columns = [ { key: 'priority', render: (val) => <span className={...}>{val}</span> }, { key: 'action', render: (_, row) => <button onClick={() => alert(row.title)}>Click Me</button> } ]; return <DataTb columns={columns} ... />}// YourPage.mdximport AdvancedTable from '@components/AdvancedTable';
<AdvancedTable client:load />Props API
DataTbProps
| Prop | Type | Default | Description |
|---|---|---|---|
csv | string | — | URL to a CSV file |
json | any[] | string | — | Inline array or URL to JSON |
api | string | — | API endpoint URL (returns array) |
directus | DirectusShorthand | — | Directus collection shorthand |
source | SourceConfig | — | Advanced source configuration |
columns | ColumnConfig[] | auto-detected | Column definitions |
searchable | boolean | false | Show global search box |
pagination | boolean | PaginationConfig | false | Enable pagination |
sortable | boolean | true | Enable column sorting |
initialSort | { columnKey, direction } | — | Default sort state |
truncateContent | boolean | true | Truncate long cell values |
truncateMaxWidth | string | '20rem' | CSS max-width for truncated cells |
contentSize | 'sm' | 'md' | 'sm' | Table body font size |
loadingMessage | string | — | Custom loading text |
emptyMessage | string | — | Custom empty-state text |
errorMessage | string | — | Custom error text |
ColumnConfig
interface ColumnConfig { key: string; // Data property key header: string; // Display header sortable?: boolean; format?: 'date' | 'number' | 'currency' | 'percent'; labels?: Record<string, string>; // Value mapping, e.g. { "true": "Yes" } width?: string; // CSS width render?: (value: any, row: DataRow) => React.ReactNode;}PaginationConfig
interface PaginationConfig { pageSize?: number; // Default: 10 showPageSize?: boolean; // Show page-size selector pageSizeOptions?: number[];}SourceConfig (advanced)
type SourceConfig = | { type: 'csv'; url: string; delimiter?: string; skipRows?: number; } | { type: 'json'; data?: any[]; url?: string; } | { type: 'api'; url: string; method?: 'GET'|'POST'; headers?: Record<string,string>; transformer?: (data: any) => any[]; } | { type: 'directus'; config: { url: string; token: string; }; collection: string; filter?: ...; fields?: ...; limit?: number; } | { type: 'geojson'; url?: string; data?: any; } | { type: 'vector'; url?: string; }DirectusShorthand
interface DirectusShorthand { table: string; queryString?: string; // e.g. "filter[status][_eq]=published&limit=10" url?: string; // defaults to PUBLIC_DIRECTUS_URL env var token?: string; // defaults to PUBLIC_DIRECTUS_TOKEN env var}Accessibility
- Full keyboard navigation for sorting and pagination
- Proper ARIA labels and table semantics
- Clear focus indicators and logical tab order
- Accessible loading and error state announcements