Components
Data
Components for displaying and managing data
Data Components
Components for displaying and managing tabular data.
Table
Display data in a table with sorting.
Basic Usage
import { Table } from '@/components/ui/Table'
<Table
columns={[
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' },
]}
data={users}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | Column[] | - | Table columns |
data | any[] | - | Table data |
loading | boolean | false | Show loading state |
onRowClick | (row) => void | - | Row click handler |
Examples
const columns = [
{ key: 'id', label: 'ID' },
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' },
{ key: 'status', label: 'Status' },
]
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
]
// Basic table
<Table
columns={columns}
data={users}
/>
// With loading state
<Table
columns={columns}
data={users}
loading={isLoading}
/>
// With row click
<Table
columns={columns}
data={users}
onRowClick={(user) => router.push(`/users/${user.id}`)}
/>
// Custom cell rendering
const columns = [
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' },
{
key: 'status',
label: 'Status',
render: (value) => (
<StatusBadge
status={value}
variant={value === 'active' ? 'success' : 'ghost'}
/>
)
},
{
key: 'actions',
label: 'Actions',
render: (_, row) => (
<div className="flex gap-2">
<Button size="sm" onClick={() => handleEdit(row)}>Edit</Button>
<Button size="sm" variant="error" onClick={() => handleDelete(row)}>Delete</Button>
</div>
)
},
]Pagination
Navigate through pages of data.
Basic Usage
import { Pagination } from '@/components/ui/Pagination'
<Pagination
currentPage={page}
totalPages={totalPages}
onPageChange={setPage}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
currentPage | number | - | Current page number |
totalPages | number | - | Total number of pages |
onPageChange | (page) => void | - | Page change handler |
showFirstLast | boolean | true | Show first/last buttons |
Examples
const [page, setPage] = useState(1)
const pageSize = 10
const totalItems = 100
const totalPages = Math.ceil(totalItems / pageSize)
// Basic pagination
<Pagination
currentPage={page}
totalPages={totalPages}
onPageChange={setPage}
/>
// Without first/last buttons
<Pagination
currentPage={page}
totalPages={totalPages}
onPageChange={setPage}
showFirstLast={false}
/>Modal
Display content in a modal dialog.
Basic Usage
import { Modal } from '@/components/ui/Modal'
<Modal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Modal Title"
>
<p>Modal content</p>
</Modal>Props
| Prop | Type | Default | Description |
|---|---|---|---|
isOpen | boolean | - | Control modal visibility |
onClose | () => void | - | Close handler |
title | string | - | Modal title |
size | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Modal size |
showCloseButton | boolean | true | Show close button |
Examples
const [isOpen, setIsOpen] = useState(false)
// Basic modal
<Modal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Confirm Action"
>
<p>Are you sure you want to continue?</p>
<div className="flex gap-2 mt-4">
<Button onClick={() => setIsOpen(false)}>Cancel</Button>
<Button variant="primary" onClick={handleConfirm}>Confirm</Button>
</div>
</Modal>
// Large modal
<Modal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="User Details"
size="lg"
>
<div className="space-y-4">
<Input label="Name" value={user.name} />
<Input label="Email" value={user.email} />
<Button>Save Changes</Button>
</div>
</Modal>
// Form modal
<Modal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Create User"
>
<form onSubmit={handleSubmit} className="space-y-4">
<Input
label="Name"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
<Input
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<div className="flex gap-2">
<Button type="submit">Create</Button>
<Button type="button" variant="ghost" onClick={() => setIsOpen(false)}>
Cancel
</Button>
</div>
</form>
</Modal>Complete Data Table Example
Full example with table, pagination, and modal:
import { useState } from 'react'
import { Table } from '@/components/ui/Table'
import { Pagination } from '@/components/ui/Pagination'
import { Modal } from '@/components/ui/Modal'
import { Button } from '@/components/ui/Button'
import { Input } from '@/components/ui/Input'
import { StatusBadge } from '@/components/ui/StatusBadge'
export function UserTable() {
const [page, setPage] = useState(1)
const [isModalOpen, setIsModalOpen] = useState(false)
const [selectedUser, setSelectedUser] = useState(null)
const pageSize = 10
const { data: users, isLoading } = useUsers({ page, pageSize })
const totalPages = Math.ceil(users?.total / pageSize)
const columns = [
{ key: 'id', label: 'ID' },
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' },
{
key: 'status',
label: 'Status',
render: (value) => (
<StatusBadge
status={value}
variant={value === 'active' ? 'success' : 'ghost'}
label={value}
/>
)
},
{
key: 'actions',
label: 'Actions',
render: (_, row) => (
<div className="flex gap-2">
<Button
size="sm"
onClick={() => {
setSelectedUser(row)
setIsModalOpen(true)
}}
>
Edit
</Button>
<Button
size="sm"
variant="error"
onClick={() => handleDelete(row.id)}
>
Delete
</Button>
</div>
)
},
]
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h2 className="text-2xl font-bold">Users</h2>
<Button onClick={() => {
setSelectedUser(null)
setIsModalOpen(true)
}}>
Add User
</Button>
</div>
<Table
columns={columns}
data={users?.items || []}
loading={isLoading}
/>
<Pagination
currentPage={page}
totalPages={totalPages}
onPageChange={setPage}
/>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title={selectedUser ? 'Edit User' : 'Create User'}
>
<UserForm
user={selectedUser}
onSuccess={() => {
setIsModalOpen(false)
refetch()
}}
/>
</Modal>
</div>
)
}Next Steps
- Form Components - Buttons, inputs
- Display Components - Cards, alerts
- Utility Components - Language, theme selectors