AxTable provides a powerful data table component with responsive behavior, row states, and automatic column management. On mobile devices, tables automatically switch to a card-based layout.
Basic Usage
import { AxTable } from 'axmed-design-system'
import type { ColumnsType } from 'antd/es/table'
interface Medication {
key: string
name: string
manufacturer: string
unitPrice: number
quantity: number
status: string
}
const columns: ColumnsType<Medication> = [
{ title: 'Medication', dataIndex: 'name', key: 'name' },
{ title: 'Manufacturer', dataIndex: 'manufacturer', key: 'manufacturer' },
{ title: 'Unit Price', dataIndex: 'unitPrice', key: 'unitPrice', align: 'right' },
{ title: 'Quantity', dataIndex: 'quantity', key: 'quantity', align: 'right' },
]
const data: Medication[] = [
{ key: '1', name: 'Amoxicillin 500mg', manufacturer: 'Cipla Ltd', unitPrice: 0.45, quantity: 12000, status: 'In Stock' },
{ key: '2', name: 'Metformin 850mg', manufacturer: 'Novartis', unitPrice: 0.32, quantity: 8500, status: 'In Stock' },
]
function Example() {
return <AxTable columns={columns} dataSource={data} />
}
<AxTable
columns={columns}
dataSource={data}
pagination={{
pageSize: 10,
showSizeChanger: true,
showTotal: (total) => `${total} medications`,
}}
/>
Sorting
Add sorter functions to columns:
const columns = [
{
title: 'Medication',
dataIndex: 'name',
key: 'name',
sorter: (a, b) => a.name.localeCompare(b.name),
},
{
title: 'Unit Price',
dataIndex: 'unitPrice',
key: 'unitPrice',
align: 'right',
sorter: (a, b) => a.unitPrice - b.unitPrice,
},
]
Filtering
const columns = [
{
title: 'Status',
dataIndex: 'status',
key: 'status',
filters: [
{ text: 'In Stock', value: 'In Stock' },
{ text: 'Low Stock', value: 'Low Stock' },
{ text: 'Out of Stock', value: 'Out of Stock' },
],
onFilter: (value, record) => record.status === value,
},
]
Row States
Highlight selected or disabled rows:
import { useState } from 'react'
function TableWithSelection() {
const [selectedKeys, setSelectedKeys] = useState(['1', '3'])
const disabledKeys = ['5'] // Rows that cannot be selected
// Build rowStates object
const rowStates = {}
disabledKeys.forEach(key => rowStates[key] = 'disabled')
selectedKeys.forEach(key => rowStates[key] = 'selected')
return (
<AxTable
columns={columns}
dataSource={data}
rowStates={rowStates}
rowSelection={{
selectedRowKeys: selectedKeys,
onChange: setSelectedKeys,
getCheckboxProps: (record) => ({
disabled: disabledKeys.includes(record.key)
}),
}}
/>
)
}
Custom Cell Rendering
Status Tags
import { AxTag } from 'axmed-design-system'
const columns = [
{
title: 'Status',
dataIndex: 'status',
key: 'status',
render: (status: string) => {
const toneMap = {
'In Stock': 'success',
'Low Stock': 'warning',
'Out of Stock': 'error',
}
return <AxTag tone={toneMap[status]}>{status}</AxTag>
},
},
]
Two-Line Cell
import { AxText } from 'axmed-design-system'
const columns = [
{
title: 'Medication',
dataIndex: 'name',
key: 'name',
render: (name: string, record: any) => (
<div>
<AxText variant="body-sm" weight="medium">{name}</AxText>
<AxText variant="body-xs" color="secondary">
{record.dosage} · {record.form}
</AxText>
</div>
),
},
]
Expandable Rows
Show additional details when clicking a row:
<AxTable
columns={columns}
dataSource={data}
expandable={{
expandedRowRender: (record) => (
<div style={{ padding: 16 }}>
<div><strong>Generic Name:</strong> {record.genericName}</div>
<div><strong>Batch Number:</strong> {record.batchNumber}</div>
<div><strong>Expiry Date:</strong> {record.expiryDate}</div>
</div>
),
}}
/>
Horizontal Scroll
For tables with many columns:
<AxTable
columns={columns}
dataSource={data}
scroll={{ x: 1500 }}
/>
Use fixed: 'left' or fixed: 'right' on columns to keep them visible while scrolling.
Responsive Behavior
Auto-Responsive Columns
By default, middle columns automatically hide as the viewport shrinks. The first and last columns always stay visible.
// Columns hide automatically right-to-left across xl → lg → md breakpoints
<AxTable
columns={columns}
dataSource={data}
autoResponsive={true} {/* default */}
/>
Mobile Card Layout
On screens below 576px, tables automatically switch to a card-based layout:
<AxTable
columns={columns}
dataSource={data}
mobileLayout="cards" {/* default - auto-switches on mobile */}
mobilePageSize={5} {/* limit cards per page on mobile */}
/>
Set mobileLayout="scroll" to keep the table scrollable on mobile instead.
Common Patterns
With Action Buttons
import { AxButton } from 'axmed-design-system'
import { EditOutlined, EyeOutlined } from '@ant-design/icons'
const columns = [
// ... other columns
{
title: 'Actions',
key: 'actions',
align: 'center',
width: 120,
render: (_, record) => (
<div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
<AxButton variant="text" size="small" icon={<EditOutlined />} />
<AxButton variant="text" size="small" icon={<EyeOutlined />} />
</div>
),
},
]
Empty State
import { AxEmptyState, AxButton } from 'axmed-design-system'
import { InboxOutlined } from '@ant-design/icons'
<AxTable
columns={columns}
dataSource={[]}
locale={{
emptyText: (
<AxEmptyState
size="sm"
illustration={<InboxOutlined style={{ fontSize: 48, color: 'var(--neutral-300)' }} />}
title="No medications found"
description="Try adjusting your filters or search term."
action={<AxButton size="small">Clear Filters</AxButton>}
/>
),
}}
/>
Props
Column definitions with title, dataIndex, key, and render functions
Array of data records to display
rowStates
Record<string | number, 'selected' | 'disabled'>
Visual state per row key: selected (blue) or disabled (reduced opacity)
rowKey
string | function
default:"key"
Key property name or function to extract unique row keys
Pagination config or false to disable
Automatically hide middle columns as viewport shrinks
Layout on mobile: cards (stacked cards) or scroll (horizontal scroll)
Page size for mobile card view
Show loading spinner overlay
Table density: small, middle, or large
See the full API reference for all available props.