Comprehensive examples showcasing all components and features. Each example includes working code and demonstrates real-world usage patterns.
Simple table with column sorting functionality. Click column headers to sort data.
| ID | Name | Department | Status | |
|---|---|---|---|---|
| 4 | Alice Brown | alice.brown@example.com | Marketing | active |
| 3 | Bob Johnson | bob.johnson@example.com | Design | active |
| 5 | Charlie Wilson | charlie.wilson@example.com | Engineering | pending |
| 6 | Diana Davis | diana.davis@example.com | Finance | active |
| 7 | Eva Garcia | eva.garcia@example.com | Engineering | inactive |
| 8 | Frank Miller | frank.miller@example.com | Design | active |
| 9 | Grace Lee | grace.lee@example.com | HR | active |
| 10 | Henry Taylor | henry.taylor@example.com | Engineering | pending |
| 11 | Ivy Anderson | ivy.anderson@example.com | Finance | active |
| 12 | Jack Thompson | jack.thompson@example.com | Design | active |
| ID | Name | Department | Status | |
|---|---|---|---|---|
| 4 | Alice Brown | alice.brown@example.com | Marketing | active |
| 3 | Bob Johnson | bob.johnson@example.com | Design | active |
| 5 | Charlie Wilson | charlie.wilson@example.com | Engineering | pending |
| 6 | Diana Davis | diana.davis@example.com | Finance | active |
| 7 | Eva Garcia | eva.garcia@example.com | Engineering | inactive |
| 8 | Frank Miller | frank.miller@example.com | Design | active |
| 9 | Grace Lee | grace.lee@example.com | HR | active |
| 10 | Henry Taylor | henry.taylor@example.com | Engineering | pending |
| 11 | Ivy Anderson | ivy.anderson@example.com | Finance | active |
| 12 | Jack Thompson | jack.thompson@example.com | Design | active |
import React from 'react';
import { Badge } from 'react-bootstrap';
import { DataTable } from '@jasperoosthoek/react-toolbox';
const BasicDataTableExample = () => {
const columns = [
{ name: 'ID', orderBy: 'id', selector: 'id', search: 'id' },
{ name: 'Name', orderBy: 'name', selector: 'name', search: 'name' },
{ name: 'Email', orderBy: 'email', selector: 'email', search: 'email' },
{ name: 'Department', orderBy: 'department', selector: 'department', search: 'department' },
{
name: 'Status',
orderBy: 'status',
selector: (user: User) => (
<Badge className={getStatusBadge(user.status)}>
{user.status}
</Badge>
),
search: ({ status }: User) => status,
},
];
return (
<DataTable
data={mockUsers}
columns={columns}
orderByDefault="name"
orderByDefaultDirection="asc"
/>
);
};
export default BasicDataTableExample;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
{
id: 4,
name: 'Alice Brown',
email: 'alice.brown@example.com',
role: 'Manager',
department: 'Marketing',
joinDate: '2022-11-05',
status: 'active',
salary: 90000,
},
{
id: 5,
name: 'Charlie Wilson',
email: 'charlie.wilson@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-04-12',
status: 'pending',
salary: 72000,
},
{
id: 6,
name: 'Diana Davis',
email: 'diana.davis@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-01-30',
status: 'active',
salary: 68000,
},
{
id: 7,
name: 'Eva Garcia',
email: 'eva.garcia@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-05-15',
status: 'inactive',
salary: 76000,
},
{
id: 8,
name: 'Frank Miller',
email: 'frank.miller@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-03-08',
status: 'active',
salary: 71000,
},
{
id: 9,
name: 'Grace Lee',
email: 'grace.lee@example.com',
role: 'Manager',
department: 'HR',
joinDate: '2022-12-01',
status: 'active',
salary: 85000,
},
{
id: 10,
name: 'Henry Taylor',
email: 'henry.taylor@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-06-01',
status: 'pending',
salary: 74000,
},
{
id: 11,
name: 'Ivy Anderson',
email: 'ivy.anderson@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-02-20',
status: 'active',
salary: 69000,
},
{
id: 12,
name: 'Jack Thompson',
email: 'jack.thompson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-04-05',
status: 'active',
salary: 73000,
},
{
id: 13,
name: 'Kate Rodriguez',
email: 'kate.rodriguez@example.com',
role: 'Product Manager',
department: 'Product',
joinDate: '2022-10-12',
status: 'active',
salary: 95000,
},
{
id: 14,
name: 'Liam Chen',
email: 'liam.chen@example.com',
role: 'Senior Developer',
department: 'Engineering',
joinDate: '2022-08-30',
status: 'active',
salary: 88000,
},
{
id: 15,
name: 'Maya Patel',
email: 'maya.patel@example.com',
role: 'UX Designer',
department: 'Design',
joinDate: '2023-01-18',
status: 'active',
salary: 77000,
},
{
id: 16,
name: 'Noah Williams',
email: 'noah.williams@example.com',
role: 'DevOps Engineer',
department: 'Engineering',
joinDate: '2023-07-10',
status: 'pending',
salary: 82000,
},
{
id: 17,
name: 'Olivia Martinez',
email: 'olivia.martinez@example.com',
role: 'Marketing Specialist',
department: 'Marketing',
joinDate: '2023-05-22',
status: 'active',
salary: 62000,
},
{
id: 18,
name: 'Patrick O\'Connor',
email: 'patrick.oconnor@example.com',
role: 'Sales Manager',
department: 'Sales',
joinDate: '2022-09-14',
status: 'active',
salary: 78000,
},
{
id: 19,
name: 'Quinn Foster',
email: 'quinn.foster@example.com',
role: 'Data Analyst',
department: 'Analytics',
joinDate: '2023-04-28',
status: 'active',
salary: 65000,
},
{
id: 20,
name: 'Rachel Kim',
email: 'rachel.kim@example.com',
role: 'QA Engineer',
department: 'Engineering',
joinDate: '2023-03-15',
status: 'inactive',
salary: 67000,
},
{
id: 21,
name: 'Samuel Green',
email: 'samuel.green@example.com',
role: 'Technical Writer',
department: 'Documentation',
joinDate: '2023-06-08',
status: 'active',
salary: 58000,
},
{
id: 22,
name: 'Tara Singh',
email: 'tara.singh@example.com',
role: 'HR Specialist',
department: 'HR',
joinDate: '2022-11-20',
status: 'active',
salary: 55000,
},
{
id: 23,
name: 'Ulysses Jackson',
email: 'ulysses.jackson@example.com',
role: 'Security Engineer',
department: 'Security',
joinDate: '2023-02-03',
status: 'active',
salary: 92000,
},
{
id: 24,
name: 'Victoria Zhou',
email: 'victoria.zhou@example.com',
role: 'Business Analyst',
department: 'Strategy',
joinDate: '2023-01-09',
status: 'pending',
salary: 71000,
},
{
id: 25,
name: 'William Brooks',
email: 'william.brooks@example.com',
role: 'Customer Success',
department: 'Support',
joinDate: '2023-05-03',
status: 'active',
salary: 59000,
},
{
id: 26,
name: 'Xara Volkov',
email: 'xara.volkov@example.com',
role: 'AI Researcher',
department: 'Research',
joinDate: '2022-12-15',
status: 'active',
salary: 105000,
},
{
id: 27,
name: 'Yuki Tanaka',
email: 'yuki.tanaka@example.com',
role: 'Intern',
department: 'Engineering',
joinDate: '2023-07-01',
status: 'pending',
salary: 45000,
},
];
// Helper function
const getStatusBadge = (status: string) => {
const statusClasses = {
active: 'badge bg-success',
inactive: 'badge bg-secondary',
pending: 'badge bg-warning',
delivered: 'badge bg-success',
shipped: 'badge bg-info',
processing: 'badge bg-warning',
};
return statusClasses[status as keyof typeof statusClasses] || 'badge bg-secondary';
};Table with built-in pagination controls and customizable page sizes plus sum calculations.
| Name | Role | Salary | Join Date | |
|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | $85,000.00 | Jan 15, 2023 |
| Jane Smith | jane.smith@example.com | Developer | $75,000.00 | Mar 20, 2023 |
| Bob Johnson | bob.johnson@example.com | Designer | $70,000.00 | Feb 10, 2023 |
| Alice Brown | alice.brown@example.com | Manager | $90,000.00 | Nov 5, 2022 |
| Charlie Wilson | charlie.wilson@example.com | Developer | $72,000.00 | Apr 12, 2023 |
| Total | $392,000.00 |
| Name | Role | Salary | Join Date | |
|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | $85,000.00 | Jan 15, 2023 |
| Jane Smith | jane.smith@example.com | Developer | $75,000.00 | Mar 20, 2023 |
| Bob Johnson | bob.johnson@example.com | Designer | $70,000.00 | Feb 10, 2023 |
| Alice Brown | alice.brown@example.com | Manager | $90,000.00 | Nov 5, 2022 |
| Charlie Wilson | charlie.wilson@example.com | Developer | $72,000.00 | Apr 12, 2023 |
| Total | $392,000.00 |
import React from 'react';
import { DataTable } from '@jasperoosthoek/react-toolbox';
const PaginatedDataTableExample = () => {
const columns = [
{ name: 'Name', orderBy: 'name', selector: 'name', search: 'name', formatSum: 'Total' },
{ name: 'Email', orderBy: 'email', selector: 'email', search: 'email' },
{ name: 'Role', orderBy: 'role', selector: 'role', search: 'role' },
{
name: 'Salary',
orderBy: 'salary',
selector: (user: User) => formatCurrency(user.salary),
search: ({ salary }: User) => salary,
value: 'salary',
formatSum: formatCurrency,
},
{
name: 'Join Date',
orderBy: 'joinDate',
selector: (user: User) => formatDate(user.joinDate),
search: ({ joinDate }: User) => joinDate,
},
];
return (
<DataTable
data={mockUsers}
columns={columns}
rowsPerPageOptions={[5, 10, 25, null]}
rowsPerPage={5}
showSum
/>
);
};
export default PaginatedDataTableExample;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
{
id: 4,
name: 'Alice Brown',
email: 'alice.brown@example.com',
role: 'Manager',
department: 'Marketing',
joinDate: '2022-11-05',
status: 'active',
salary: 90000,
},
{
id: 5,
name: 'Charlie Wilson',
email: 'charlie.wilson@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-04-12',
status: 'pending',
salary: 72000,
},
{
id: 6,
name: 'Diana Davis',
email: 'diana.davis@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-01-30',
status: 'active',
salary: 68000,
},
{
id: 7,
name: 'Eva Garcia',
email: 'eva.garcia@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-05-15',
status: 'inactive',
salary: 76000,
},
{
id: 8,
name: 'Frank Miller',
email: 'frank.miller@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-03-08',
status: 'active',
salary: 71000,
},
{
id: 9,
name: 'Grace Lee',
email: 'grace.lee@example.com',
role: 'Manager',
department: 'HR',
joinDate: '2022-12-01',
status: 'active',
salary: 85000,
},
{
id: 10,
name: 'Henry Taylor',
email: 'henry.taylor@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-06-01',
status: 'pending',
salary: 74000,
},
{
id: 11,
name: 'Ivy Anderson',
email: 'ivy.anderson@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-02-20',
status: 'active',
salary: 69000,
},
{
id: 12,
name: 'Jack Thompson',
email: 'jack.thompson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-04-05',
status: 'active',
salary: 73000,
},
{
id: 13,
name: 'Kate Rodriguez',
email: 'kate.rodriguez@example.com',
role: 'Product Manager',
department: 'Product',
joinDate: '2022-10-12',
status: 'active',
salary: 95000,
},
{
id: 14,
name: 'Liam Chen',
email: 'liam.chen@example.com',
role: 'Senior Developer',
department: 'Engineering',
joinDate: '2022-08-30',
status: 'active',
salary: 88000,
},
{
id: 15,
name: 'Maya Patel',
email: 'maya.patel@example.com',
role: 'UX Designer',
department: 'Design',
joinDate: '2023-01-18',
status: 'active',
salary: 77000,
},
{
id: 16,
name: 'Noah Williams',
email: 'noah.williams@example.com',
role: 'DevOps Engineer',
department: 'Engineering',
joinDate: '2023-07-10',
status: 'pending',
salary: 82000,
},
{
id: 17,
name: 'Olivia Martinez',
email: 'olivia.martinez@example.com',
role: 'Marketing Specialist',
department: 'Marketing',
joinDate: '2023-05-22',
status: 'active',
salary: 62000,
},
{
id: 18,
name: 'Patrick O\'Connor',
email: 'patrick.oconnor@example.com',
role: 'Sales Manager',
department: 'Sales',
joinDate: '2022-09-14',
status: 'active',
salary: 78000,
},
{
id: 19,
name: 'Quinn Foster',
email: 'quinn.foster@example.com',
role: 'Data Analyst',
department: 'Analytics',
joinDate: '2023-04-28',
status: 'active',
salary: 65000,
},
{
id: 20,
name: 'Rachel Kim',
email: 'rachel.kim@example.com',
role: 'QA Engineer',
department: 'Engineering',
joinDate: '2023-03-15',
status: 'inactive',
salary: 67000,
},
{
id: 21,
name: 'Samuel Green',
email: 'samuel.green@example.com',
role: 'Technical Writer',
department: 'Documentation',
joinDate: '2023-06-08',
status: 'active',
salary: 58000,
},
{
id: 22,
name: 'Tara Singh',
email: 'tara.singh@example.com',
role: 'HR Specialist',
department: 'HR',
joinDate: '2022-11-20',
status: 'active',
salary: 55000,
},
{
id: 23,
name: 'Ulysses Jackson',
email: 'ulysses.jackson@example.com',
role: 'Security Engineer',
department: 'Security',
joinDate: '2023-02-03',
status: 'active',
salary: 92000,
},
{
id: 24,
name: 'Victoria Zhou',
email: 'victoria.zhou@example.com',
role: 'Business Analyst',
department: 'Strategy',
joinDate: '2023-01-09',
status: 'pending',
salary: 71000,
},
{
id: 25,
name: 'William Brooks',
email: 'william.brooks@example.com',
role: 'Customer Success',
department: 'Support',
joinDate: '2023-05-03',
status: 'active',
salary: 59000,
},
{
id: 26,
name: 'Xara Volkov',
email: 'xara.volkov@example.com',
role: 'AI Researcher',
department: 'Research',
joinDate: '2022-12-15',
status: 'active',
salary: 105000,
},
{
id: 27,
name: 'Yuki Tanaka',
email: 'yuki.tanaka@example.com',
role: 'Intern',
department: 'Engineering',
joinDate: '2023-07-01',
status: 'pending',
salary: 45000,
},
];
// Helper functions
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount);
};
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
});
}Interactive table with row click to edit functionality and action buttons.
| Name | Role | Status | Actions | |
|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | active | |
| Jane Smith | jane.smith@example.com | Developer | active | |
| Bob Johnson | bob.johnson@example.com | Designer | active | |
| Alice Brown | alice.brown@example.com | Manager | active | |
| Charlie Wilson | charlie.wilson@example.com | Developer | pending | |
| Diana Davis | diana.davis@example.com | Analyst | active | |
| Eva Garcia | eva.garcia@example.com | Developer | inactive | |
| Frank Miller | frank.miller@example.com | Designer | active | |
| Grace Lee | grace.lee@example.com | Manager | active | |
| Henry Taylor | henry.taylor@example.com | Developer | pending |
| Name | Role | Status | Actions | |
|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | active | |
| Jane Smith | jane.smith@example.com | Developer | active | |
| Bob Johnson | bob.johnson@example.com | Designer | active | |
| Alice Brown | alice.brown@example.com | Manager | active | |
| Charlie Wilson | charlie.wilson@example.com | Developer | pending | |
| Diana Davis | diana.davis@example.com | Analyst | active | |
| Eva Garcia | eva.garcia@example.com | Developer | inactive | |
| Frank Miller | frank.miller@example.com | Designer | active | |
| Grace Lee | grace.lee@example.com | Manager | active | |
| Henry Taylor | henry.taylor@example.com | Developer | pending |
import React, { useState } from 'react';
import { Badge, ButtonGroup } from 'react-bootstrap';
import {
DataTable,
FormProvider,
FormModal,
EditButton,
DeleteConfirmButton
} from '@jasperoosthoek/react-toolbox';
const EditableDataTableExample = () => {
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [showModal, setShowModal] = useState<boolean>(false);
const [users, setUsers] = useState<User[]>(mockUsers);
const columns = [
{ name: 'Name', orderBy: 'name', selector: 'name', search: 'name' },
{ name: 'Email', orderBy: 'email', selector: 'email', search: 'email' },
{ name: 'Role', orderBy: 'role', selector: 'role', search: 'role' },
{
name: 'Status',
orderBy: 'status',
selector: (user: User) => (
<Badge className={getStatusBadge(user.status)}>
{user.status}
</Badge>
),
search: ({ status }: User) => status,
},
{
name: 'Actions',
className: 'text-center',
selector: (user: User) => (
<ButtonGroup size="sm">
<EditButton onClick={() => handleRowClick(user)} />
<DeleteConfirmButton
onDelete={() => handleDelete(user.id)}
size="sm"
/>
</ButtonGroup>
)
},
];
const handleRowClick = (user: User) => {
setSelectedUser(user);
setShowModal(true);
};
const handleEditSubmit = (data: any, callback?: () => void) => {
setUsers(users.map(user =>
user.id === selectedUser?.id
? { ...user, ...data }
: user
));
setTimeout(() => {
setShowModal(false);
setSelectedUser(null);
if (callback) callback();
}, 1000);
};
const handleDelete = (userId: number) => {
setUsers(users.filter(user => user.id !== userId));
};
const formFields = {
name: {
label: 'Name',
required: true,
initialValue: selectedUser?.name || '',
},
email: {
label: 'Email',
required: true,
initialValue: selectedUser?.email || '',
},
role: {
label: 'Role',
required: true,
initialValue: selectedUser?.role || '',
},
status: {
label: 'Status',
type: 'select' as const,
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
],
initialValue: selectedUser?.status || 'active',
},
};
return (
<div>
<DataTable
data={users}
columns={columns}
onClickRow={handleRowClick}
rowClassName="table-row-hover"
/>
{showModal && selectedUser && (
<FormProvider
formFields={formFields}
onSubmit={handleEditSubmit}
resetTrigger={selectedUser.id}
>
<FormModal
show={showModal}
onHide={() => setShowModal(false)}
modalTitle={`Edit ${selectedUser.name}`}
submitText="Save Changes"
cancelText="Cancel"
/>
</FormProvider>
)}
</div>
);
};
export default EditableDataTableExample;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
{
id: 4,
name: 'Alice Brown',
email: 'alice.brown@example.com',
role: 'Manager',
department: 'Marketing',
joinDate: '2022-11-05',
status: 'active',
salary: 90000,
},
{
id: 5,
name: 'Charlie Wilson',
email: 'charlie.wilson@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-04-12',
status: 'pending',
salary: 72000,
},
{
id: 6,
name: 'Diana Davis',
email: 'diana.davis@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-01-30',
status: 'active',
salary: 68000,
},
{
id: 7,
name: 'Eva Garcia',
email: 'eva.garcia@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-05-15',
status: 'inactive',
salary: 76000,
},
{
id: 8,
name: 'Frank Miller',
email: 'frank.miller@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-03-08',
status: 'active',
salary: 71000,
},
{
id: 9,
name: 'Grace Lee',
email: 'grace.lee@example.com',
role: 'Manager',
department: 'HR',
joinDate: '2022-12-01',
status: 'active',
salary: 85000,
},
{
id: 10,
name: 'Henry Taylor',
email: 'henry.taylor@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-06-01',
status: 'pending',
salary: 74000,
},
{
id: 11,
name: 'Ivy Anderson',
email: 'ivy.anderson@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-02-20',
status: 'active',
salary: 69000,
},
{
id: 12,
name: 'Jack Thompson',
email: 'jack.thompson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-04-05',
status: 'active',
salary: 73000,
},
{
id: 13,
name: 'Kate Rodriguez',
email: 'kate.rodriguez@example.com',
role: 'Product Manager',
department: 'Product',
joinDate: '2022-10-12',
status: 'active',
salary: 95000,
},
{
id: 14,
name: 'Liam Chen',
email: 'liam.chen@example.com',
role: 'Senior Developer',
department: 'Engineering',
joinDate: '2022-08-30',
status: 'active',
salary: 88000,
},
{
id: 15,
name: 'Maya Patel',
email: 'maya.patel@example.com',
role: 'UX Designer',
department: 'Design',
joinDate: '2023-01-18',
status: 'active',
salary: 77000,
},
{
id: 16,
name: 'Noah Williams',
email: 'noah.williams@example.com',
role: 'DevOps Engineer',
department: 'Engineering',
joinDate: '2023-07-10',
status: 'pending',
salary: 82000,
},
{
id: 17,
name: 'Olivia Martinez',
email: 'olivia.martinez@example.com',
role: 'Marketing Specialist',
department: 'Marketing',
joinDate: '2023-05-22',
status: 'active',
salary: 62000,
},
{
id: 18,
name: 'Patrick O\'Connor',
email: 'patrick.oconnor@example.com',
role: 'Sales Manager',
department: 'Sales',
joinDate: '2022-09-14',
status: 'active',
salary: 78000,
},
{
id: 19,
name: 'Quinn Foster',
email: 'quinn.foster@example.com',
role: 'Data Analyst',
department: 'Analytics',
joinDate: '2023-04-28',
status: 'active',
salary: 65000,
},
{
id: 20,
name: 'Rachel Kim',
email: 'rachel.kim@example.com',
role: 'QA Engineer',
department: 'Engineering',
joinDate: '2023-03-15',
status: 'inactive',
salary: 67000,
},
{
id: 21,
name: 'Samuel Green',
email: 'samuel.green@example.com',
role: 'Technical Writer',
department: 'Documentation',
joinDate: '2023-06-08',
status: 'active',
salary: 58000,
},
{
id: 22,
name: 'Tara Singh',
email: 'tara.singh@example.com',
role: 'HR Specialist',
department: 'HR',
joinDate: '2022-11-20',
status: 'active',
salary: 55000,
},
{
id: 23,
name: 'Ulysses Jackson',
email: 'ulysses.jackson@example.com',
role: 'Security Engineer',
department: 'Security',
joinDate: '2023-02-03',
status: 'active',
salary: 92000,
},
{
id: 24,
name: 'Victoria Zhou',
email: 'victoria.zhou@example.com',
role: 'Business Analyst',
department: 'Strategy',
joinDate: '2023-01-09',
status: 'pending',
salary: 71000,
},
{
id: 25,
name: 'William Brooks',
email: 'william.brooks@example.com',
role: 'Customer Success',
department: 'Support',
joinDate: '2023-05-03',
status: 'active',
salary: 59000,
},
{
id: 26,
name: 'Xara Volkov',
email: 'xara.volkov@example.com',
role: 'AI Researcher',
department: 'Research',
joinDate: '2022-12-15',
status: 'active',
salary: 105000,
},
{
id: 27,
name: 'Yuki Tanaka',
email: 'yuki.tanaka@example.com',
role: 'Intern',
department: 'Engineering',
joinDate: '2023-07-01',
status: 'pending',
salary: 45000,
},
];
// Helper function
const getStatusBadge = (status: string) => {
const statusClasses = {
active: 'badge bg-success',
inactive: 'badge bg-secondary',
pending: 'badge bg-warning',
delivered: 'badge bg-success',
shipped: 'badge bg-info',
processing: 'badge bg-warning',
};
return statusClasses[status as keyof typeof statusClasses] || 'badge bg-secondary';
};Drag rows to reorder them with server persistence and error handling plus sum calculations.
| Name | Category | Price | Stock | Tags |
|---|---|---|---|---|
| Total | $2,805.90 |
| Name | Category | Price | Stock | Tags |
|---|---|---|---|---|
| Total | $2,805.90 |
import React, { useState } from 'react';
import { Badge, Alert } from 'react-bootstrap';
import { DataTable, FixedLoadingIndicator } from '@jasperoosthoek/react-toolbox';
const DragDropDataTableExample = () => {
const [products, setProducts] = useState(mockProducts);
const [isMoving, setIsMoving] = useState(false);
const columns = [
{ name: 'Name', orderBy: 'name', selector: 'name', search: 'name', formatSum: 'Total' },
{ name: 'Category', orderBy: 'category', selector: 'category', search: 'category' },
{
name: 'Price',
orderBy: 'price',
selector: (product: Product) => formatCurrency(product.price),
search: ({ price }: Product) => price,
value: 'price',
formatSum: formatCurrency,
},
{
name: 'Stock',
orderBy: 'stock',
selector: (product: Product) => (
<Badge bg={product.stock > 50 ? 'success' : product.stock > 20 ? 'warning' : 'danger'}>
{product.stock}
</Badge>
),
search: ({ stock }: Product) => stock,
},
{
name: 'Tags',
selector: (product: Product) => (
<span>
{product.tags.map((tag, index) => (
<Badge key={index} bg="secondary" className="me-1">
{tag}
</Badge>
))}
</span>
),
search: ({ tags }: Product) => tags.join(' '),
},
];
const handleMove = ({ item, target, reset }: { item: Product; target: Product; reset: () => void }) => {
setIsMoving(true);
// Get current positions
const currentData = [...products];
const itemIndex = currentData.findIndex(p => p.id === item.id);
const targetIndex = currentData.findIndex(p => p.id === target.id);
// Remove item from current position
const [movedItem] = currentData.splice(itemIndex, 1);
// Insert at new position
currentData.splice(targetIndex, 0, movedItem);
// Update state immediately (optimistic update)
setProducts(currentData);
// Simulate API call to save new order
setTimeout(() => {
const success = Math.random() > 0.2;
if (success) {
setIsMoving(false);
} else {
reset(); // Reset to original position on failure
setIsMoving(false);
}
}, 1500);
};
return (
<div>
<FixedLoadingIndicator
show={isMoving}
message="Saving new order..."
variant="info"
/>
<DataTable
data={products}
columns={columns}
onMove={handleMove}
moveIsLoading={isMoving}
showSum
/>
</div>
);
};
export default DragDropDataTableExample;
// Types and Mock Data
interface Product {
id: number;
name: string;
category: string;
price: number;
stock: number;
description: string;
tags: string[];
}
const mockProducts: Product[] = [
{
id: 1,
name: 'Laptop Pro',
category: 'Electronics',
price: 1299.99,
stock: 45,
description: 'High-performance laptop for professionals',
tags: [
'laptop',
'computer',
'work',
],
},
{
id: 2,
name: 'Wireless Mouse',
category: 'Electronics',
price: 29.99,
stock: 120,
description: 'Ergonomic wireless mouse',
tags: [
'mouse',
'wireless',
'office',
],
},
{
id: 3,
name: 'Office Chair',
category: 'Furniture',
price: 249.99,
stock: 18,
description: 'Comfortable ergonomic office chair',
tags: [
'chair',
'office',
'furniture',
],
},
{
id: 4,
name: 'Monitor 27"',
category: 'Electronics',
price: 329.99,
stock: 32,
description: '27-inch 4K monitor',
tags: [
'monitor',
'display',
'screen',
],
},
{
id: 5,
name: 'Keyboard Mechanical',
category: 'Electronics',
price: 89.99,
stock: 67,
description: 'Mechanical keyboard with RGB lighting',
tags: [
'keyboard',
'mechanical',
'RGB',
],
},
{
id: 6,
name: 'Standing Desk',
category: 'Furniture',
price: 399.99,
stock: 12,
description: 'Adjustable height standing desk',
tags: [
'desk',
'standing',
'adjustable',
],
},
{
id: 7,
name: 'Webcam HD',
category: 'Electronics',
price: 79.99,
stock: 85,
description: '1080p HD webcam with noise cancellation',
tags: [
'webcam',
'camera',
'video',
],
},
{
id: 8,
name: 'Wireless Headphones',
category: 'Electronics',
price: 159.99,
stock: 54,
description: 'Noise-cancelling wireless headphones',
tags: [
'headphones',
'wireless',
'audio',
],
},
{
id: 9,
name: 'Desk Lamp LED',
category: 'Office Supplies',
price: 45.99,
stock: 73,
description: 'Adjustable LED desk lamp with USB charging',
tags: [
'lamp',
'LED',
'desk',
],
},
{
id: 10,
name: 'External Hard Drive',
category: 'Electronics',
price: 119.99,
stock: 41,
description: '2TB portable external hard drive',
tags: [
'storage',
'drive',
'portable',
],
},
{
id: 11,
name: 'Tablet Pro',
category: 'Electronics',
price: 649.99,
stock: 28,
description: '11-inch professional tablet with stylus',
tags: [
'tablet',
'stylus',
'mobile',
],
},
{
id: 12,
name: 'Smartphone Case',
category: 'Accessories',
price: 24.99,
stock: 156,
description: 'Protective smartphone case with card holder',
tags: [
'case',
'phone',
'protection',
],
},
{
id: 13,
name: 'Coffee Maker Pro',
category: 'Appliances',
price: 189.99,
stock: 22,
description: 'Programmable coffee maker with grinder',
tags: [
'coffee',
'maker',
'appliance',
],
},
{
id: 14,
name: 'Bookshelf Oak',
category: 'Furniture',
price: 179.99,
stock: 15,
description: '5-shelf oak wood bookshelf',
tags: [
'bookshelf',
'wood',
'storage',
],
},
{
id: 15,
name: 'Wireless Charger',
category: 'Electronics',
price: 34.99,
stock: 98,
description: 'Fast wireless charging pad',
tags: [
'charger',
'wireless',
'charging',
],
},
{
id: 16,
name: 'Gaming Mouse Pad',
category: 'Accessories',
price: 19.99,
stock: 134,
description: 'Large RGB gaming mouse pad',
tags: [
'mousepad',
'gaming',
'RGB',
],
},
{
id: 17,
name: 'Bluetooth Speaker',
category: 'Electronics',
price: 69.99,
stock: 67,
description: 'Portable waterproof Bluetooth speaker',
tags: [
'speaker',
'bluetooth',
'portable',
],
},
{
id: 18,
name: 'File Cabinet',
category: 'Furniture',
price: 124.99,
stock: 9,
description: '3-drawer locking file cabinet',
tags: [
'cabinet',
'filing',
'storage',
],
},
{
id: 19,
name: 'USB Hub',
category: 'Electronics',
price: 39.99,
stock: 76,
description: '7-port USB 3.0 hub with power adapter',
tags: [
'USB',
'hub',
'connectivity',
],
},
{
id: 20,
name: 'Desk Organizer',
category: 'Office Supplies',
price: 16.99,
stock: 112,
description: 'Bamboo desk organizer with compartments',
tags: [
'organizer',
'bamboo',
'desk',
],
},
{
id: 21,
name: 'Monitor Arm',
category: 'Accessories',
price: 89.99,
stock: 33,
description: 'Dual monitor mounting arm',
tags: [
'mount',
'monitor',
'arm',
],
},
{
id: 22,
name: 'Printer Laser',
category: 'Electronics',
price: 299.99,
stock: 17,
description: 'Wireless laser printer with scanner',
tags: [
'printer',
'laser',
'scanner',
],
},
{
id: 23,
name: 'Ergonomic Footrest',
category: 'Furniture',
price: 49.99,
stock: 44,
description: 'Adjustable ergonomic footrest',
tags: [
'footrest',
'ergonomic',
'adjustable',
],
},
{
id: 24,
name: 'Cable Management Kit',
category: 'Office Supplies',
price: 12.99,
stock: 89,
description: 'Complete cable management solution',
tags: [
'cable',
'management',
'organization',
],
},
{
id: 25,
name: 'Smart Watch',
category: 'Electronics',
price: 249.99,
stock: 38,
description: 'Fitness tracking smart watch',
tags: [
'watch',
'smart',
'fitness',
],
},
{
id: 26,
name: 'Whiteboard Magnetic',
category: 'Office Supplies',
price: 69.99,
stock: 25,
description: 'Large magnetic whiteboard with markers',
tags: [
'whiteboard',
'magnetic',
'markers',
],
},
{
id: 27,
name: 'Document Shredder',
category: 'Office Equipment',
price: 159.99,
stock: 14,
description: 'Cross-cut document shredder',
tags: [
'shredder',
'document',
'security',
],
},
{
id: 28,
name: 'Air Purifier',
category: 'Appliances',
price: 199.99,
stock: 19,
description: 'HEPA air purifier with smart controls',
tags: [
'purifier',
'air',
'HEPA',
],
},
{
id: 29,
name: 'Laptop Stand',
category: 'Accessories',
price: 54.99,
stock: 61,
description: 'Adjustable aluminum laptop stand',
tags: [
'stand',
'laptop',
'aluminum',
],
},
{
id: 30,
name: 'Wireless Keyboard',
category: 'Electronics',
price: 59.99,
stock: 78,
description: 'Compact wireless keyboard with number pad',
tags: [
'keyboard',
'wireless',
'compact',
],
},
{
id: 31,
name: 'Desk Mat Leather',
category: 'Office Supplies',
price: 35.99,
stock: 52,
description: 'Premium leather desk mat',
tags: [
'mat',
'leather',
'premium',
],
},
{
id: 32,
name: 'Security Camera',
category: 'Electronics',
price: 129.99,
stock: 26,
description: 'Indoor security camera with night vision',
tags: [
'camera',
'security',
'surveillance',
],
},
{
id: 33,
name: 'Stapler Heavy Duty',
category: 'Office Supplies',
price: 22.99,
stock: 67,
description: 'Heavy-duty stapler for thick documents',
tags: [
'stapler',
'heavy-duty',
'office',
],
},
{
id: 34,
name: 'Power Bank',
category: 'Electronics',
price: 44.99,
stock: 83,
description: '20000mAh portable power bank',
tags: [
'power',
'bank',
'portable',
],
},
{
id: 35,
name: 'Task Chair Mesh',
category: 'Furniture',
price: 189.99,
stock: 21,
description: 'Breathable mesh task chair',
tags: [
'chair',
'mesh',
'task',
],
},
];
// Helper function
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount);
};Advanced rendering with dropdown status updates, action buttons, column filters, and sum calculations.
| Order ID | Customer | Product | Quantity | Total | Status | Actions |
|---|---|---|---|---|---|---|
| #1001 | John Doe | Laptop Pro | 1 | $1,299.99 | ||
| #1002 | Jane Smith | Wireless Mouse | 2 | $59.98 | ||
| #1003 | Bob Johnson | Office Chair | 1 | $249.99 | ||
| #1004 | Alice Brown | Monitor 27" | 2 | $659.98 | ||
| #1005 | Charlie Wilson | Keyboard Mechanical | 1 | $89.99 | ||
| Total | 7 | $2,359.93 |
| Order ID | Customer | Product | Quantity | Total | Status | Actions |
|---|---|---|---|---|---|---|
| #1001 | John Doe | Laptop Pro | 1 | $1,299.99 | ||
| #1002 | Jane Smith | Wireless Mouse | 2 | $59.98 | ||
| #1003 | Bob Johnson | Office Chair | 1 | $249.99 | ||
| #1004 | Alice Brown | Monitor 27" | 2 | $659.98 | ||
| #1005 | Charlie Wilson | Keyboard Mechanical | 1 | $89.99 | ||
| Total | 7 | $2,359.93 |
import React, { useState } from 'react';
import { Badge, Button, ButtonGroup, Dropdown } from 'react-bootstrap';
import { DataTable } from '@jasperoosthoek/react-toolbox';
const CustomRendererDataTableExample = () => {
const [orders, setOrders] = useState(mockOrders);
const statusOptions = {
pending: 'Pending',
processing: 'Processing',
shipped: 'Shipped',
delivered: 'Delivered',
};
const updateOrderStatus = (orderId: number, newStatus: string) => {
setOrders(orders.map(order =>
order.id === orderId
? { ...order, status: newStatus as Order['status'] }
: order
));
};
const columns = [
{
name: 'Order ID',
orderBy: 'id',
selector: (order: Order) => `#${order.id}`,
search: 'id',
formatSum: 'Total'
},
{ name: 'Customer', orderBy: 'customerName', selector: 'customerName', search: 'customerName' },
{ name: 'Product', orderBy: 'product', selector: 'product', search: 'product' },
{
name: 'Quantity',
orderBy: 'quantity',
selector: 'quantity',
search: 'quantity',
value: 'quantity',
},
{
name: 'Total',
orderBy: 'total',
selector: (order: Order) => formatCurrency(order.total),
search: ({ total }: Order) => total,
value: 'total',
formatSum: formatCurrency,
},
{
name: 'Status',
orderBy: 'status',
selector: (order: Order) => (
<Dropdown>
<Dropdown.Toggle
variant="outline-secondary"
size="sm"
className={getStatusBadge(order.status)}
>
{order.status}
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => updateOrderStatus(order.id, 'pending')}>
Pending
</Dropdown.Item>
<Dropdown.Item onClick={() => updateOrderStatus(order.id, 'processing')}>
Processing
</Dropdown.Item>
<Dropdown.Item onClick={() => updateOrderStatus(order.id, 'shipped')}>
Shipped
</Dropdown.Item>
<Dropdown.Item onClick={() => updateOrderStatus(order.id, 'delivered')}>
Delivered
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
),
search: ({ status }: Order) => status,
optionsDropdown: {
onSelect: (key: string | null) => {
console.log('Filter by status:', key);
},
selected: null,
options: statusOptions,
}
},
{
name: 'Actions',
className: 'text-center',
selector: (order: Order) => (
<ButtonGroup size="sm">
<Button variant="outline-primary" size="sm">
View
</Button>
<Button variant="outline-secondary" size="sm">
Print
</Button>
</ButtonGroup>
)
},
];
return (
<DataTable
data={orders}
columns={columns}
rowsPerPageOptions={[5, 10, 25, null]}
rowsPerPage={5}
showSum
/>
);
};
export default CustomRendererDataTableExample;
// Types and Mock Data
interface Order {
id: number;
customerName: string;
product: string;
quantity: number;
total: number;
status: 'pending' | 'processing' | 'shipped' | 'delivered';
orderDate: string;
}
const mockOrders: Order[] = [
{
id: 1001,
customerName: 'John Doe',
product: 'Laptop Pro',
quantity: 1,
total: 1299.99,
status: 'delivered',
orderDate: '2023-06-15',
},
{
id: 1002,
customerName: 'Jane Smith',
product: 'Wireless Mouse',
quantity: 2,
total: 59.98,
status: 'shipped',
orderDate: '2023-06-18',
},
{
id: 1003,
customerName: 'Bob Johnson',
product: 'Office Chair',
quantity: 1,
total: 249.99,
status: 'processing',
orderDate: '2023-06-20',
},
{
id: 1004,
customerName: 'Alice Brown',
product: 'Monitor 27"',
quantity: 2,
total: 659.98,
status: 'pending',
orderDate: '2023-06-22',
},
{
id: 1005,
customerName: 'Charlie Wilson',
product: 'Keyboard Mechanical',
quantity: 1,
total: 89.99,
status: 'delivered',
orderDate: '2023-06-14',
},
{
id: 1006,
customerName: 'Diana Davis',
product: 'Standing Desk',
quantity: 1,
total: 399.99,
status: 'shipped',
orderDate: '2023-06-25',
},
{
id: 1007,
customerName: 'Eva Garcia',
product: 'Webcam HD',
quantity: 1,
total: 79.99,
status: 'delivered',
orderDate: '2023-06-12',
},
{
id: 1008,
customerName: 'Frank Miller',
product: 'Wireless Headphones',
quantity: 1,
total: 159.99,
status: 'processing',
orderDate: '2023-06-28',
},
{
id: 1009,
customerName: 'Grace Lee',
product: 'Desk Lamp LED',
quantity: 2,
total: 91.98,
status: 'delivered',
orderDate: '2023-06-10',
},
{
id: 1010,
customerName: 'Henry Taylor',
product: 'External Hard Drive',
quantity: 1,
total: 119.99,
status: 'pending',
orderDate: '2023-06-30',
},
{
id: 1011,
customerName: 'Ivy Anderson',
product: 'Tablet Pro',
quantity: 1,
total: 649.99,
status: 'shipped',
orderDate: '2023-06-26',
},
{
id: 1012,
customerName: 'Jack Thompson',
product: 'Smartphone Case',
quantity: 3,
total: 74.97,
status: 'delivered',
orderDate: '2023-06-08',
},
{
id: 1013,
customerName: 'Kate Rodriguez',
product: 'Coffee Maker Pro',
quantity: 1,
total: 189.99,
status: 'processing',
orderDate: '2023-06-29',
},
{
id: 1014,
customerName: 'Liam Chen',
product: 'Bookshelf Oak',
quantity: 1,
total: 179.99,
status: 'delivered',
orderDate: '2023-06-05',
},
{
id: 1015,
customerName: 'Maya Patel',
product: 'Wireless Charger',
quantity: 2,
total: 69.98,
status: 'shipped',
orderDate: '2023-06-27',
},
{
id: 1016,
customerName: 'Noah Williams',
product: 'Gaming Mouse Pad',
quantity: 1,
total: 19.99,
status: 'delivered',
orderDate: '2023-06-11',
},
{
id: 1017,
customerName: 'Olivia Martinez',
product: 'Bluetooth Speaker',
quantity: 1,
total: 69.99,
status: 'pending',
orderDate: '2023-07-01',
},
{
id: 1018,
customerName: 'Patrick O\'Connor',
product: 'File Cabinet',
quantity: 2,
total: 249.98,
status: 'processing',
orderDate: '2023-06-24',
},
{
id: 1019,
customerName: 'Quinn Foster',
product: 'USB Hub',
quantity: 1,
total: 39.99,
status: 'delivered',
orderDate: '2023-06-07',
},
{
id: 1020,
customerName: 'Rachel Kim',
product: 'Desk Organizer',
quantity: 3,
total: 50.97,
status: 'shipped',
orderDate: '2023-06-23',
},
{
id: 1021,
customerName: 'Samuel Green',
product: 'Monitor Arm',
quantity: 1,
total: 89.99,
status: 'delivered',
orderDate: '2023-06-09',
},
{
id: 1022,
customerName: 'Tara Singh',
product: 'Printer Laser',
quantity: 1,
total: 299.99,
status: 'processing',
orderDate: '2023-06-28',
},
{
id: 1023,
customerName: 'Ulysses Jackson',
product: 'Ergonomic Footrest',
quantity: 1,
total: 49.99,
status: 'delivered',
orderDate: '2023-06-06',
},
{
id: 1024,
customerName: 'Victoria Zhou',
product: 'Cable Management Kit',
quantity: 4,
total: 51.96,
status: 'shipped',
orderDate: '2023-06-21',
},
{
id: 1025,
customerName: 'William Brooks',
product: 'Smart Watch',
quantity: 1,
total: 249.99,
status: 'pending',
orderDate: '2023-07-02',
},
{
id: 1026,
customerName: 'Xara Volkov',
product: 'Whiteboard Magnetic',
quantity: 1,
total: 69.99,
status: 'delivered',
orderDate: '2023-06-04',
},
{
id: 1027,
customerName: 'Yuki Tanaka',
product: 'Document Shredder',
quantity: 1,
total: 159.99,
status: 'processing',
orderDate: '2023-06-26',
},
{
id: 1028,
customerName: 'Alex Thompson',
product: 'Air Purifier',
quantity: 1,
total: 199.99,
status: 'delivered',
orderDate: '2023-06-03',
},
{
id: 1029,
customerName: 'Betty Chen',
product: 'Laptop Stand',
quantity: 2,
total: 109.98,
status: 'shipped',
orderDate: '2023-06-19',
},
{
id: 1030,
customerName: 'Carlos Rodriguez',
product: 'Wireless Keyboard',
quantity: 1,
total: 59.99,
status: 'delivered',
orderDate: '2023-06-02',
},
{
id: 1031,
customerName: 'Deborah Adams',
product: 'Desk Mat Leather',
quantity: 1,
total: 35.99,
status: 'pending',
orderDate: '2023-07-03',
},
{
id: 1032,
customerName: 'Eric Johnson',
product: 'Security Camera',
quantity: 2,
total: 259.98,
status: 'processing',
orderDate: '2023-06-25',
},
{
id: 1033,
customerName: 'Fiona Walsh',
product: 'Stapler Heavy Duty',
quantity: 3,
total: 68.97,
status: 'delivered',
orderDate: '2023-06-01',
},
{
id: 1034,
customerName: 'George Kim',
product: 'Power Bank',
quantity: 1,
total: 44.99,
status: 'shipped',
orderDate: '2023-06-17',
},
{
id: 1035,
customerName: 'Helen Foster',
product: 'Task Chair Mesh',
quantity: 1,
total: 189.99,
status: 'delivered',
orderDate: '2023-05-31',
},
{
id: 1036,
customerName: 'Ian Martinez',
product: 'Laptop Pro',
quantity: 1,
total: 1299.99,
status: 'processing',
orderDate: '2023-06-27',
},
{
id: 1037,
customerName: 'Julia Brown',
product: 'Wireless Mouse',
quantity: 4,
total: 119.96,
status: 'pending',
orderDate: '2023-07-04',
},
{
id: 1038,
customerName: 'Kevin Lee',
product: 'Office Chair',
quantity: 1,
total: 249.99,
status: 'delivered',
orderDate: '2023-05-30',
},
{
id: 1039,
customerName: 'Luna Garcia',
product: 'Monitor 27"',
quantity: 1,
total: 329.99,
status: 'shipped',
orderDate: '2023-06-16',
},
{
id: 1040,
customerName: 'Michael Davis',
product: 'Keyboard Mechanical',
quantity: 2,
total: 179.98,
status: 'delivered',
orderDate: '2023-05-29',
},
{
id: 1041,
customerName: 'Nina Patel',
product: 'Standing Desk',
quantity: 1,
total: 399.99,
status: 'processing',
orderDate: '2023-06-24',
},
{
id: 1042,
customerName: 'Oscar Wilson',
product: 'Webcam HD',
quantity: 3,
total: 239.97,
status: 'pending',
orderDate: '2023-07-05',
},
{
id: 1043,
customerName: 'Penny Anderson',
product: 'Wireless Headphones',
quantity: 1,
total: 159.99,
status: 'delivered',
orderDate: '2023-05-28',
},
{
id: 1044,
customerName: 'Quincy Miller',
product: 'Desk Lamp LED',
quantity: 1,
total: 45.99,
status: 'shipped',
orderDate: '2023-06-13',
},
{
id: 1045,
customerName: 'Ruby Taylor',
product: 'External Hard Drive',
quantity: 2,
total: 239.98,
status: 'delivered',
orderDate: '2023-05-27',
},
{
id: 1046,
customerName: 'Steve Jackson',
product: 'Tablet Pro',
quantity: 1,
total: 649.99,
status: 'processing',
orderDate: '2023-06-22',
},
{
id: 1047,
customerName: 'Tina Zhou',
product: 'Smartphone Case',
quantity: 5,
total: 124.95,
status: 'pending',
orderDate: '2023-07-06',
},
{
id: 1048,
customerName: 'Udo Schmidt',
product: 'Coffee Maker Pro',
quantity: 1,
total: 189.99,
status: 'delivered',
orderDate: '2023-05-26',
},
{
id: 1049,
customerName: 'Vera Nguyen',
product: 'Bookshelf Oak',
quantity: 2,
total: 359.98,
status: 'shipped',
orderDate: '2023-06-11',
},
{
id: 1050,
customerName: 'Walter Brooks',
product: 'Wireless Charger',
quantity: 1,
total: 34.99,
status: 'delivered',
orderDate: '2023-05-25',
},
{
id: 1051,
customerName: 'Xenia Volkov',
product: 'Gaming Mouse Pad',
quantity: 2,
total: 39.98,
status: 'processing',
orderDate: '2023-06-20',
},
{
id: 1052,
customerName: 'Yasmin Ali',
product: 'Bluetooth Speaker',
quantity: 1,
total: 69.99,
status: 'pending',
orderDate: '2023-07-07',
},
{
id: 1053,
customerName: 'Zach Cooper',
product: 'File Cabinet',
quantity: 1,
total: 124.99,
status: 'delivered',
orderDate: '2023-05-24',
},
];
// Helper functions
const getStatusBadge = (status: string) => {
const statusClasses = {
active: 'badge bg-success',
inactive: 'badge bg-secondary',
pending: 'badge bg-warning',
delivered: 'badge bg-success',
shipped: 'badge bg-info',
processing: 'badge bg-warning',
};
return statusClasses[status as keyof typeof statusClasses] || 'badge bg-secondary';
};
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount);
};Complete CRUD operations with seamless form modal integration for create and edit operations.
| Name | Role | Department | Status | Actions | |
|---|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | Engineering | active | |
| Jane Smith | jane.smith@example.com | Developer | Engineering | active | |
| Bob Johnson | bob.johnson@example.com | Designer | Design | active | |
| Alice Brown | alice.brown@example.com | Manager | Marketing | active | |
| Charlie Wilson | charlie.wilson@example.com | Developer | Engineering | pending |
| Name | Role | Department | Status | Actions | |
|---|---|---|---|---|---|
| John Doe | john.doe@example.com | Admin | Engineering | active | |
| Jane Smith | jane.smith@example.com | Developer | Engineering | active | |
| Bob Johnson | bob.johnson@example.com | Designer | Design | active | |
| Alice Brown | alice.brown@example.com | Manager | Marketing | active | |
| Charlie Wilson | charlie.wilson@example.com | Developer | Engineering | pending |
import React, { useState } from 'react';
import { Badge, ButtonGroup } from 'react-bootstrap';
import {
DataTable,
FormModalProvider,
FormCreateModalButton,
FormEditModalButton,
DeleteConfirmButton
} from '@jasperoosthoek/react-toolbox';
const IntegratedFormDataTableExample = () => {
const [users, setUsers] = useState(mockUsers);
const formFields = {
name: {
label: 'Full Name',
required: true,
initialValue: '',
},
email: {
label: 'Email',
required: true,
initialValue: '',
},
role: {
label: 'Role',
required: true,
initialValue: '',
},
department: {
label: 'Department',
type: 'select' as const,
options: [
{ value: 'Engineering', label: 'Engineering' },
{ value: 'Design', label: 'Design' },
{ value: 'Marketing', label: 'Marketing' },
{ value: 'Finance', label: 'Finance' },
{ value: 'HR', label: 'HR' },
],
initialValue: '',
},
status: {
label: 'Status',
type: 'select' as const,
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
],
initialValue: 'active',
},
};
const handleCreate = (data: any, callback?: () => void) => {
const newUser: User = {
id: Math.max(...users.map(u => u.id)) + 1,
...data,
joinDate: new Date().toISOString().split('T')[0],
salary: 70000, // Default salary
};
setUsers([...users, newUser]);
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const handleUpdate = (data: any, callback?: () => void) => {
setUsers(users.map(user =>
user.id === data.id ? { ...user, ...data } : user
));
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const handleDelete = (userId: number) => {
setUsers(users.filter(user => user.id !== userId));
};
const columns = [
{ name: 'Name', orderBy: 'name', selector: 'name', search: 'name' },
{ name: 'Email', orderBy: 'email', selector: 'email', search: 'email' },
{ name: 'Role', orderBy: 'role', selector: 'role', search: 'role' },
{ name: 'Department', orderBy: 'department', selector: 'department', search: 'department' },
{
name: 'Status',
orderBy: 'status',
selector: (user: User) => (
<Badge className={getStatusBadge(user.status)}>
{user.status}
</Badge>
),
search: ({ status }: User) => status,
},
{ name: 'Actions', className: 'text-center', selector: (user: User) => (
<ButtonGroup size="sm">
<FormEditModalButton state={user} variant="outline-primary" size="sm" />
<DeleteConfirmButton
onDelete={() => handleDelete(user.id)}
variant="outline-primary"
size="sm"
/>
</ButtonGroup>
) },
];
return (
<FormModalProvider
formFields={formFields}
onCreate={handleCreate}
onUpdate={handleUpdate}
createModalTitle="Add New Employee"
editModalTitle="Edit Employee"
>
<div>
<div className="d-flex justify-content-between mb-3">
<h5>Employee Management</h5>
<FormCreateModalButton variant="primary">
Add Employee
</FormCreateModalButton>
</div>
<DataTable
data={users}
columns={columns}
rowsPerPageOptions={[5, 10, 25, null]}
rowsPerPage={5}
/>
</div>
</FormModalProvider>
);
};
export default IntegratedFormDataTableExample;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
{
id: 4,
name: 'Alice Brown',
email: 'alice.brown@example.com',
role: 'Manager',
department: 'Marketing',
joinDate: '2022-11-05',
status: 'active',
salary: 90000,
},
{
id: 5,
name: 'Charlie Wilson',
email: 'charlie.wilson@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-04-12',
status: 'pending',
salary: 72000,
},
{
id: 6,
name: 'Diana Davis',
email: 'diana.davis@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-01-30',
status: 'active',
salary: 68000,
},
{
id: 7,
name: 'Eva Garcia',
email: 'eva.garcia@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-05-15',
status: 'inactive',
salary: 76000,
},
{
id: 8,
name: 'Frank Miller',
email: 'frank.miller@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-03-08',
status: 'active',
salary: 71000,
},
{
id: 9,
name: 'Grace Lee',
email: 'grace.lee@example.com',
role: 'Manager',
department: 'HR',
joinDate: '2022-12-01',
status: 'active',
salary: 85000,
},
{
id: 10,
name: 'Henry Taylor',
email: 'henry.taylor@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-06-01',
status: 'pending',
salary: 74000,
},
{
id: 11,
name: 'Ivy Anderson',
email: 'ivy.anderson@example.com',
role: 'Analyst',
department: 'Finance',
joinDate: '2023-02-20',
status: 'active',
salary: 69000,
},
{
id: 12,
name: 'Jack Thompson',
email: 'jack.thompson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-04-05',
status: 'active',
salary: 73000,
},
{
id: 13,
name: 'Kate Rodriguez',
email: 'kate.rodriguez@example.com',
role: 'Product Manager',
department: 'Product',
joinDate: '2022-10-12',
status: 'active',
salary: 95000,
},
{
id: 14,
name: 'Liam Chen',
email: 'liam.chen@example.com',
role: 'Senior Developer',
department: 'Engineering',
joinDate: '2022-08-30',
status: 'active',
salary: 88000,
},
{
id: 15,
name: 'Maya Patel',
email: 'maya.patel@example.com',
role: 'UX Designer',
department: 'Design',
joinDate: '2023-01-18',
status: 'active',
salary: 77000,
},
{
id: 16,
name: 'Noah Williams',
email: 'noah.williams@example.com',
role: 'DevOps Engineer',
department: 'Engineering',
joinDate: '2023-07-10',
status: 'pending',
salary: 82000,
},
{
id: 17,
name: 'Olivia Martinez',
email: 'olivia.martinez@example.com',
role: 'Marketing Specialist',
department: 'Marketing',
joinDate: '2023-05-22',
status: 'active',
salary: 62000,
},
{
id: 18,
name: 'Patrick O\'Connor',
email: 'patrick.oconnor@example.com',
role: 'Sales Manager',
department: 'Sales',
joinDate: '2022-09-14',
status: 'active',
salary: 78000,
},
{
id: 19,
name: 'Quinn Foster',
email: 'quinn.foster@example.com',
role: 'Data Analyst',
department: 'Analytics',
joinDate: '2023-04-28',
status: 'active',
salary: 65000,
},
{
id: 20,
name: 'Rachel Kim',
email: 'rachel.kim@example.com',
role: 'QA Engineer',
department: 'Engineering',
joinDate: '2023-03-15',
status: 'inactive',
salary: 67000,
},
{
id: 21,
name: 'Samuel Green',
email: 'samuel.green@example.com',
role: 'Technical Writer',
department: 'Documentation',
joinDate: '2023-06-08',
status: 'active',
salary: 58000,
},
{
id: 22,
name: 'Tara Singh',
email: 'tara.singh@example.com',
role: 'HR Specialist',
department: 'HR',
joinDate: '2022-11-20',
status: 'active',
salary: 55000,
},
{
id: 23,
name: 'Ulysses Jackson',
email: 'ulysses.jackson@example.com',
role: 'Security Engineer',
department: 'Security',
joinDate: '2023-02-03',
status: 'active',
salary: 92000,
},
{
id: 24,
name: 'Victoria Zhou',
email: 'victoria.zhou@example.com',
role: 'Business Analyst',
department: 'Strategy',
joinDate: '2023-01-09',
status: 'pending',
salary: 71000,
},
{
id: 25,
name: 'William Brooks',
email: 'william.brooks@example.com',
role: 'Customer Success',
department: 'Support',
joinDate: '2023-05-03',
status: 'active',
salary: 59000,
},
{
id: 26,
name: 'Xara Volkov',
email: 'xara.volkov@example.com',
role: 'AI Researcher',
department: 'Research',
joinDate: '2022-12-15',
status: 'active',
salary: 105000,
},
{
id: 27,
name: 'Yuki Tanaka',
email: 'yuki.tanaka@example.com',
role: 'Intern',
department: 'Engineering',
joinDate: '2023-07-01',
status: 'pending',
salary: 45000,
},
];
// Helper function
const getStatusBadge = (status: string) => {
const statusClasses = {
active: 'badge bg-success',
inactive: 'badge bg-secondary',
pending: 'badge bg-warning',
delivered: 'badge bg-success',
shipped: 'badge bg-info',
processing: 'badge bg-warning',
};
return statusClasses[status as keyof typeof statusClasses] || 'badge bg-secondary';
};Using FormProvider with direct component usage for maximum flexibility
import React from 'react';
import { Button } from 'react-bootstrap';
import {
FormProvider,
FormInput,
FormCheckbox,
useForm
} from '@jasperoosthoek/react-toolbox';
const MyForm = () => {
const formFields = {
name: { required: true, initialValue: '' },
email: { required: true, initialValue: '' },
age: { type: 'number' as const, initialValue: 0 },
newsletter: { initialValue: false }
};
const handleSubmit = (data: any, callback?: () => void) => {
console.log('Form submitted:', data);
// API call here
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const validate = (data: any) => {
const errors: any = {};
if (data.email && !data.email.includes('@')) {
errors.email = 'Invalid email format';
}
if (data.age && (data.age < 0 || data.age > 120)) {
errors.age = 'Age must be between 0 and 120';
}
return errors;
};
const SubmitButton = () => {
const { submit, loading } = useForm();
return (
<Button
onClick={submit}
disabled={loading}
variant="primary"
>
{loading ? 'Submitting...' : 'Submit'}
</Button>
);
};
return (
<FormProvider
formFields={formFields}
onSubmit={handleSubmit}
validate={validate}
>
<FormInput
name="name"
label="Full Name"
placeholder="Enter your full name"
/>
<FormInput
name="email"
label="Email Address"
type="email"
placeholder="Enter your email"
/>
<FormInput
name="age"
label="Age"
type="number"
min={0}
max={120}
/>
<FormCheckbox
name="newsletter"
label="Subscribe to newsletter"
/>
<SubmitButton />
</FormProvider>
);
};
export default MyForm;FormModalProvider for create/edit modals with automatic state management
import React, { useState } from 'react';
import { Button, Card } from 'react-bootstrap';
import {
FormModalProvider,
FormCreateModalButton,
useFormModal
} from '@jasperoosthoek/react-toolbox';
const UserManagement = () => {
const [users, setUsers] = useState<User[]>(mockUsers);
// FormModalProvider automatically renders form fields from this config
const userFormFields = {
name: {
type: 'string' as const,
required: true,
initialValue: '',
label: 'Full Name',
formProps: { placeholder: 'Enter full name' }
},
email: {
type: 'string' as const,
required: true,
initialValue: '',
label: 'Email Address',
formProps: { type: 'email', placeholder: 'Enter email address' }
},
role: {
type: 'select' as const,
required: true,
initialValue: '',
label: 'Role',
options: [
{ value: 'Admin', label: 'Admin' },
{ value: 'Developer', label: 'Developer' },
{ value: 'Designer', label: 'Designer' },
{ value: 'Manager', label: 'Manager' },
{ value: 'Analyst', label: 'Analyst' }
]
},
department: {
type: 'select' as const,
required: true,
initialValue: '',
label: 'Department',
options: [
{ value: 'Engineering', label: 'Engineering' },
{ value: 'Design', label: 'Design' },
{ value: 'Marketing', label: 'Marketing' },
{ value: 'Finance', label: 'Finance' },
{ value: 'HR', label: 'HR' }
]
},
salary: {
type: 'number' as const,
initialValue: 0,
label: 'Salary',
formProps: { min: 0, placeholder: 'Enter salary amount' }
}
};
const handleCreate = (data: any, callback?: () => void) => {
const newUser: User = {
id: Date.now(),
...data,
joinDate: new Date().toISOString().split('T')[0],
status: 'active',
salary: 70000
};
setUsers([...users, newUser]);
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const handleUpdate = (data: any, callback?: () => void) => {
setUsers(users.map(user =>
user.id === data.id ? { ...user, ...data } : user
));
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const UserList = () => {
const { showEditModal } = useFormModal();
return (
<div>
<FormCreateModalButton variant="primary">
Create New User
</FormCreateModalButton>
<Card className="mt-3">
<Card.Body>
{users.map(user => (
<div key={user.id} className="d-flex justify-content-between mb-2 p-2 border rounded">
<div>
<strong>{user.name}</strong> - {user.role}
<br />
<small className="text-muted">{user.email}</small>
</div>
<Button
size="sm"
variant="outline-primary"
onClick={() => showEditModal(user)}
>
Edit
</Button>
</div>
))}
</Card.Body>
</Card>
</div>
);
};
return (
<FormModalProvider
formFields={userFormFields}
onCreate={handleCreate}
onUpdate={handleUpdate}
createModalTitle="Create User"
editModalTitle="Edit User"
>
<UserList />
</FormModalProvider>
);
};
export default UserManagement;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
];FormProvider with FormModal integration for complex layouts and workflows
import React, { useState } from 'react';
import { Button, Row, Col, Alert } from 'react-bootstrap';
import {
FormProvider,
FormModal,
FormInput,
FormSelect,
FormTextarea,
FormCheckbox
} from '@jasperoosthoek/react-toolbox';
const ContactForm = () => {
const [showModal, setShowModal] = useState(false);
const [editData, setEditData] = useState<any>(null);
const [submitMessage, setSubmitMessage] = useState<string>('');
const contactFormFields = {
firstName: { required: true, initialValue: '' },
lastName: { required: true, initialValue: '' },
email: { required: true, initialValue: '' },
phone: { initialValue: '' },
message: { required: true, initialValue: '' },
contactMethod: { initialValue: 'email' },
urgent: { initialValue: false }
};
const handleSubmit = (data: any, callback?: () => void) => {
console.log('Contact form submitted:', data);
setSubmitMessage(`Thank you ${data.firstName}! We'll contact you via ${data.contactMethod}.`);
setShowModal(false);
setEditData(null);
setTimeout(() => {
if (callback) callback();
setSubmitMessage('');
}, 3000);
};
const validate = (data: any) => {
const errors: any = {};
if (data.email && !data.email.match(/^[^s@]+@[^s@]+.[^s@]+$/)) {
errors.email = 'Please enter a valid email address';
}
if (data.phone && data.phone.length < 10) {
errors.phone = 'Phone number must be at least 10 digits';
}
if (data.message && data.message.length < 10) {
errors.message = 'Message must be at least 10 characters';
}
return errors;
};
const contactMethodOptions = [
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' },
{ value: 'both', label: 'Both Email and Phone' }
];
return (
<div>
{submitMessage && (
<Alert variant="success" className="mb-3">
{submitMessage}
</Alert>
)}
<div className="mb-3">
<Button
variant="primary"
onClick={() => {
setEditData(null);
setShowModal(true);
}}
>
Open Contact Form
</Button>
<Button
variant="outline-secondary"
className="ms-2"
onClick={() => {
setEditData({
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@example.com',
phone: '555-0123',
message: 'I need help with my account.',
contactMethod: 'email',
urgent: true
});
setShowModal(true);
}}
>
Edit Sample Data
</Button>
</div>
<FormProvider
formFields={contactFormFields}
onSubmit={handleSubmit}
validate={validate}
initialState={editData}
>
<FormModal
show={showModal}
onHide={() => setShowModal(false)}
modalTitle={editData ? "Edit Contact Request" : "Contact Us"}
width={75}
>
<Row>
<Col md={6}>
<FormInput name="firstName" label="First Name" />
</Col>
<Col md={6}>
<FormInput name="lastName" label="Last Name" />
</Col>
</Row>
<Row>
<Col md={6}>
<FormInput name="email" label="Email" type="email" />
</Col>
<Col md={6}>
<FormInput name="phone" label="Phone" />
</Col>
</Row>
<FormSelect
name="contactMethod"
label="Preferred Contact Method"
options={contactMethodOptions}
/>
<FormTextarea
name="message"
label="Message"
rows={4}
placeholder="Please describe how we can help you..."
/>
<FormCheckbox
name="urgent"
label="This is urgent - please prioritize my request"
/>
</FormModal>
</FormProvider>
</div>
);
}
export default ContactForm;Dynamic form rendering using FormFieldsRenderer with field configuration objects
Help us understand your background and preferences
Help us understand your background and preferences
import React, { useState } from 'react';
import { Button, Card } from 'react-bootstrap';
import {
FormProvider,
FormFieldsRenderer,
FormBadgesSelection,
FormCheckbox,
useForm
} from '@jasperoosthoek/react-toolbox';
const SurveyForm = () => {
const [formData, setFormData] = useState<any>({});
const surveyFormFields = {
name: {
required: true,
initialValue: '',
label: 'Full Name',
formProps: {
placeholder: 'Enter your full name'
},
},
age: {
type: 'number' as const,
initialValue: 0,
label: 'Age',
formProps: {
min: 18,
max: 100
}
},
experience: {
type: 'select' as const,
required: true,
initialValue: '',
label: 'Experience Level',
options: [
{ value: 'beginner', label: 'Beginner (0-2 years)' },
{ value: 'intermediate', label: 'Intermediate (3-5 years)' },
{ value: 'advanced', label: 'Advanced (6+ years)' }
]
},
skills: {
component: FormBadgesSelection,
initialValue: ['react'],
label: 'Skills',
idKey: 'value',
formProps: {
list: [
{ value: 'react', label: 'React' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'node', label: 'Node.js' },
{ value: 'python', label: 'Python' },
{ value: 'design', label: 'UI/UX Design' },
{ value: 'testing', label: 'Testing' }
],
}
},
remote: {
component: FormCheckbox,
initialValue: false,
label: 'Open to remote work'
},
comments: {
type: 'textarea' as const,
initialValue: '',
label: 'Additional Comments',
formProps: {
placeholder: 'Tell us anything else we should know...',
},
rows: 3
}
};
const handleSubmit = (data: any, callback?: () => void) => {
console.log('Survey submitted:', data);
setFormData(data);
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const SubmitButton = () => {
const { submit, loading } = useForm();
return (
<Button onClick={submit} disabled={loading}>
{loading ? 'Submitting...' : 'Submit Survey'}
</Button>
);
};
return (
<div>
<FormProvider
formFields={surveyFormFields}
onSubmit={handleSubmit}
>
<h5>Developer Survey</h5>
<p className="text-muted mb-4">
Help us understand your background and preferences
</p>
<FormFieldsRenderer />
<SubmitButton />
</FormProvider>
{Object.keys(formData).length > 0 && (
<Card className="mt-4">
<Card.Header>Submitted Data</Card.Header>
<Card.Body>
<pre>{JSON.stringify(formData, null, 2)}</pre>
</Card.Body>
</Card>
)}
</div>
);
};
export default SurveyForm;Combining direct components with convenience wrappers and advanced layouts
import React, { useState } from 'react';
import { Card, Row, Col, Button, Alert } from 'react-bootstrap';
import {
FormProvider,
FormInput,
FormDropdown,
FormSelect,
FormTextarea,
FormCheckbox,
useForm
} from '@jasperoosthoek/react-toolbox';
const OrderForm = () => {
const [orderData, setOrderData] = useState<any>({});
const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
const formFields = {
customerName: { required: true, initialValue: '' },
email: { required: true, initialValue: '' },
product: { required: true, initialValue: '' },
quantity: { type: 'number' as const, initialValue: 1 },
priority: { initialValue: 'normal' },
specialInstructions: { initialValue: '' },
newsletter: { initialValue: true },
terms: { required: true, initialValue: false }
};
const handleSubmit = (data: any, callback?: () => void) => {
console.log('Order submitted:', data);
setOrderData(data);
setTimeout(() => {
if (callback) callback();
}, 1000);
};
const validate = (data: any) => {
const errors: any = {};
if (data.email && !data.email.includes('@')) {
errors.email = 'Invalid email format';
}
if (data.quantity && data.quantity < 1) {
errors.quantity = 'Quantity must be at least 1';
}
if (!data.terms) {
errors.terms = 'You must accept the terms and conditions';
}
return errors;
};
const productOptions = [
{ value: 'laptop', label: 'Laptop Pro - $1,299' },
{ value: 'mouse', label: 'Wireless Mouse - $29' },
{ value: 'keyboard', label: 'Mechanical Keyboard - $89' },
{ value: 'monitor', label: '27" Monitor - $329' }
];
const priorityOptions = [
{ value: 'normal', label: 'Normal' },
{ value: 'high', label: 'High Priority (+$10)' },
{ value: 'urgent', label: 'Urgent (+$25)' }
];
const SubmitButton = () => {
const { submit, loading } = useForm();
return (
<Button onClick={submit} disabled={loading} variant="primary">
{loading ? 'Processing...' : 'Place Order'}
</Button>
);
};
return (
<div>
<FormProvider
formFields={formFields}
onSubmit={handleSubmit}
validate={validate}
>
<h5>Product Order Form</h5>
{/* Customer Information */}
<Card className="mb-3">
<Card.Header>Customer Information</Card.Header>
<Card.Body>
<Row>
<Col md={6}>
<FormInput
name="customerName"
label="Customer Name"
placeholder="Enter full name"
/>
</Col>
<Col md={6}>
<FormInput
name="email"
label="Email Address"
type="email"
placeholder="customer@example.com"
/>
</Col>
</Row>
</Card.Body>
</Card>
{/* Order Details */}
<Card className="mb-3">
<Card.Header>Order Details</Card.Header>
<Card.Body>
<Row>
<Col md={8}>
<FormDropdown
name="product"
label="Select Product"
list={productOptions}
placeholder="Choose a product..."
/>
</Col>
<Col md={4}>
<FormInput
name="quantity"
label="Quantity"
type="number"
min={1}
max={10}
/>
</Col>
</Row>
<FormSelect
name="priority"
label="Shipping Priority"
options={priorityOptions}
/>
</Card.Body>
</Card>
{/* Advanced Options */}
<Card className="mb-3">
<Card.Header>
<div className="d-flex justify-content-between">
<span>Additional Options</span>
<Button
variant="link"
size="sm"
onClick={() => setShowAdvanced(!showAdvanced)}
>
{showAdvanced ? 'Hide' : 'Show'} Advanced
</Button>
</div>
</Card.Header>
{showAdvanced && (
<Card.Body>
<FormTextarea
name="specialInstructions"
label="Special Instructions"
placeholder="Any special delivery instructions..."
rows={3}
/>
<FormCheckbox
name="newsletter"
label="Subscribe to updates"
/>
</Card.Body>
)}
</Card>
<FormCheckbox
name="terms"
label="I agree to the Terms and Conditions"
/>
<SubmitButton />
</FormProvider>
{Object.keys(orderData).length > 0 && (
<Alert variant="success" className="mt-4">
<h6>Order Confirmed!</h6>
<p>Thank you {orderData.customerName}! Your order has been submitted.</p>
</Alert>
)}
</div>
);
};
export default OrderForm;Demonstrate basic localization with built-in strings and the text\`localization_string\` pattern
import React from 'react';
import { ButtonGroup, Button, Badge, Card } from 'react-bootstrap';
import {
useLocalization,
defaultLanguages
} from '@jasperoosthoek/react-toolbox';
const MyLocalizationDemo = () => {
const { lang, languages, setLanguage, text } = useLocalization();
return (
<div>
<Card className="mb-4">
<Card.Header>
<div className="d-flex justify-content-between align-items-center">
<h6 className="mb-0">Language Controls</h6>
<div>
<span className="me-2">Current Language:</span>
<Badge bg="primary">{lang.toUpperCase()}</Badge>
</div>
</div>
</Card.Header>
<Card.Body>
<ButtonGroup className="mb-3">
{languages.map(language => (
<Button
key={language}
variant={lang === language ? 'primary' : 'outline-primary'}
onClick={() => setLanguage(language)}
>
{defaultLanguages[language] || language}
</Button>
))}
</ButtonGroup>
<div className="row">
<div className="col-md-6">
<h6>Basic String Examples</h6>
<div className="mb-2">
<strong>Save:</strong> {text`save`}
</div>
<div className="mb-2">
<strong>Cancel:</strong> {text`cancel`}
</div>
<div className="mb-2">
<strong>Delete:</strong> {text`delete`}
</div>
<div className="mb-2">
<strong>Search:</strong> {text`search`}
</div>
<div className="mb-2">
<strong>Are you sure?:</strong> {text`are_you_sure`}
</div>
<div className="mb-2">
<strong>Required field:</strong> {text`required_field`}
</div>
</div>
<div className="col-md-6">
<h6>UI String Examples</h6>
<div className="mb-2">
<strong>Login:</strong> {text`login`}
</div>
<div className="mb-2">
<strong>Your email:</strong> {text`your_email`}
</div>
<div className="mb-2">
<strong>Enter password:</strong> {text`enter_password`}
</div>
<div className="mb-2">
<strong>Choose one:</strong> {text`choose_one`}
</div>
<div className="mb-2">
<strong>Number of rows:</strong> {text`number_of_rows`}
</div>
<div className="mb-2">
<strong>No information:</strong> {text`no_information_to_display`}
</div>
</div>
</div>
</Card.Body>
</Card>
</div>
);
};
export default MyLocalizationDemo;Add your own localization strings with support for function interpolation and parameters
import React, { useState, useEffect } from 'react';
import { useLocalization } from '@jasperoosthoek/react-toolbox';
const CustomStringsDemo = () => {
const { text, setLocalization, textByLang } = useLocalization();
// Define custom localization strings
const customStrings = {
en: {
welcome_message: "Welcome to our application!",
user_count: (count) => `There ${count === 1 ? 'is' : 'are'} ${count} user${count === 1 ? '' : 's'} online`,
greeting: (name) => `Hello, ${name}!`,
notification: (type, message) => `${type}: ${message}`,
product_price: (name, price) => `${name} costs $${price.toFixed(2)}`,
},
fr: {
welcome_message: "Bienvenue dans notre application!",
user_count: (count) => `Il y a ${count} utilisateur${count === 1 ? '' : 's'} en ligne`,
greeting: (name) => `Bonjour, ${name}!`,
notification: (type, message) => `${type}: ${message}`,
product_price: (name, price) => `${name} coûte ${price.toFixed(2)}$`,
},
nl: {
welcome_message: "Welkom bij onze applicatie!",
user_count: (count) => `Er ${count === 1 ? 'is' : 'zijn'} ${count} gebruiker${count === 1 ? '' : 's'} online`,
greeting: (name) => `Hallo, ${name}!`,
notification: (type, message) => `${type}: ${message}`,
product_price: (name, price) => `${name} kost €${price.toFixed(2)}`,
},
};
// Add custom strings to localization
useEffect(() => {
setLocalization(customStrings);
}, []);
return (
<div>
{/* Simple string usage */}
<h2>{text`welcome_message`}</h2>
{/* Function with single parameter */}
<p>{text`greeting${'John'}`}</p>
{/* Function with number (pluralization) */}
<p>{text`user_count${1}`}</p>
<p>{text`user_count${5}`}</p>
{/* Multiple parameters */}
<div>{text`notification${'Error'}${'Something went wrong'}`}</div>
<div>{text`notification${'Success'}${'Operation completed'}`}</div>
{/* Complex function with multiple types */}
<div>{text`product_price${'Premium Plan'}${29.99}`}</div>
{/* Use specific language */}
<div>{textByLang('fr')`greeting${'Marie'}`}</div>
</div>
);
};
export default CustomStringsDemo;Forms automatically use localized strings for labels, placeholders, and validation messages
import React, { useState } from 'react';
import { Button, Alert, Card } from 'react-bootstrap';
import {
FormProvider,
FormInput,
useForm,
useLocalization,
} from '@jasperoosthoek/react-toolbox';
const LoginForm = () => {
const { text, lang } = useLocalization();
const [loginResult, setLoginResult] = useState<string>('');
const formFields = {
email: {
type: 'string' as const,
label: text`your_email`,
placeholder: text`enter_email`,
required: true,
initialValue: '',
formProps: { type: 'email' }
},
password: {
type: 'string' as const,
label: text`your_password`,
placeholder: text`enter_password`,
required: true,
initialValue: '',
formProps: { type: 'password' }
},
};
const handleSubmit = (data: any, callback?: () => void) => {
console.log('Login attempt:', data);
// Simulate login process
setLoginResult(`${text`login`} attempted with: ${data.email}`);
// Simulate API call
setTimeout(() => {
setLoginResult(`${text`login`} successful for: ${data.email}`);
if (callback) callback();
// Clear result after 3 seconds
setTimeout(() => setLoginResult(''), 3000);
}, 1000);
};
const validate = (data: any) => {
const errors: any = {};
if (data.email && !data.email.includes('@')) {
errors.email = 'Please enter a valid email address';
}
if (data.password && data.password.length < 6) {
errors.password = 'Password must be at least 6 characters';
}
return errors;
};
// Custom submit button that uses form context
const LoginButton = () => {
const { submit, loading } = useForm();
return (
<Button
onClick={submit}
disabled={loading}
variant="primary"
>
{loading ? 'Logging in...' : text`login`}
</Button>
);
};
return (
<div>
{loginResult && (
<Alert variant="success" className="mb-3">
{loginResult}
</Alert>
)}
<Card className="mb-4">
<Card.Header>
<h6 className="mb-0">{text`login`} Form</h6>
</Card.Header>
<Card.Body>
<FormProvider
formFields={formFields}
onSubmit={handleSubmit}
validate={validate}
>
<FormInput name="email" />
<FormInput name="password" />
<FormActions className="justify-content-between">
<LoginButton />
<Button
type="button"
variant="outline-secondary"
onClick={() => setLoginResult('')}
>
{text`cancel`}
</Button>
</FormActions>
</FormProvider>
</Card.Body>
</Card>
</div>
);
};
export default LoginForm;
interface FormActionsProps {
children: React.ReactNode;
className?: string;
}
const FormActions: React.FC<FormActionsProps> = ({ children, className = '' }) => {
return (
<div className={`d-flex gap-2 align-items-center mt-3 ${className}`}>
{children}
</div>
);
};DataTable components automatically use localized strings for search, pagination, and empty states
| Name | Role | Actions | |
|---|---|---|---|
| John Doe | john.doe@example.com | Admin | |
| Jane Smith | jane.smith@example.com | Developer | |
| Bob Johnson | bob.johnson@example.com | Designer |
| Name | Role | Actions | |
|---|---|---|---|
| John Doe | john.doe@example.com | Admin | |
| Jane Smith | jane.smith@example.com | Developer | |
| Bob Johnson | bob.johnson@example.com | Designer |
import React from 'react';
import { DataTable, EditButton, DeleteConfirmButton, useLocalization } from '@jasperoosthoek/react-toolbox';
const LocalizedDataTable = () => {
const { text } = useLocalization();
const users = mockUsers;
const columns = [
{ name: 'Name', orderBy: 'name', selector: 'name' },
{ name: 'Email', orderBy: 'email', selector: 'email' },
{ name: 'Role', orderBy: 'role', selector: 'role' },
{
name: 'Actions',
selector: (user: User) => (
<span>
<EditButton size="sm" title={text`modal_edit`} />
<DeleteConfirmButton
size="sm"
onDelete={() => console.log('Delete', user.id)}
/>
</span>
)
},
];
return (
<DataTable
data={users}
columns={columns}
// DataTable automatically uses localized strings for:
// - Search placeholder (text`search`)
// - Pagination text (text`number_of_rows`)
// - Empty state (text`no_information_to_display`)
// - Loading state (text`information_is_being_loaded`)
rowsPerPageOptions={[5, 10, 25, null]}
rowsPerPage={5}
/>
);
};
export default LocalizedDataTable;
// Types and Mock Data
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
joinDate: string;
status: 'active' | 'inactive' | 'pending';
salary: number;
avatar?: string;
}
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
role: 'Admin',
department: 'Engineering',
joinDate: '2023-01-15',
status: 'active',
salary: 85000,
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
role: 'Developer',
department: 'Engineering',
joinDate: '2023-03-20',
status: 'active',
salary: 75000,
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
role: 'Designer',
department: 'Design',
joinDate: '2023-02-10',
status: 'active',
salary: 70000,
},
]Build reusable language switcher components in various styles
import React from 'react';
import { Form } from 'react-bootstrap';
import { useLocalization, defaultLanguages } from '@jasperoosthoek/react-toolbox';
const LanguageSwitcher = () => {
const { lang, languages, setLanguage } = useLocalization();
return (
<Form.Select
value={lang}
onChange={(e) => setLanguage(e.target.value)}
style={{ width: '200px' }}
>
{languages.map(language => (
<option key={language} value={language}>
{defaultLanguages[language] || language}
</option>
))}
</Form.Select>
);
};
// Button Group Version
const LanguageSwitcherButtons = () => {
const { lang, languages, setLanguage } = useLocalization();
return (
<ButtonGroup>
{languages.map(language => (
<Button
key={language}
variant={lang === language ? 'primary' : 'outline-primary'}
onClick={() => setLanguage(language)}
>
{defaultLanguages[language]}
</Button>
))}
</ButtonGroup>
);
};
// Dropdown Version
const LanguageSwitcherDropdown = () => {
const { lang, languages, setLanguage } = useLocalization();
return (
<Dropdown>
<Dropdown.Toggle variant="outline-secondary">
{defaultLanguages[lang]} 🌐
</Dropdown.Toggle>
<Dropdown.Menu>
{languages.map(language => (
<Dropdown.Item
key={language}
active={lang === language}
onClick={() => setLanguage(language)}
>
{defaultLanguages[language]}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
);
};All available default localization strings and how to extend them
| Key | Value | Usage |
|---|---|---|
select | Select | text`select` |
search | Search | text`search` |
save | Save | text`save` |
cancel | Cancel | text`cancel` |
delete | Delete | text`delete` |
are_you_sure | Are you sure? | text`are_you_sure` |
close | Close | text`close` |
ok | OK | text`ok` |
login | Login | text`login` |
logout | Logout | text`logout` |
your_email | Your email | text`your_email` |
enter_email | Enter email address | text`enter_email` |
your_password | Your password | text`your_password` |
enter_password | Enter password | text`enter_password` |
required_field | required_field | text`required_field` |
choose_one | Choose one | text`choose_one` |
everything | Everything | text`everything` |
number_of_rows | Number of rows | text`number_of_rows` |
modal_create | New | text`modal_create` |
modal_edit | Edit | text`modal_edit` |
no_information_to_display | No information to display | text`no_information_to_display` |
information_is_being_loaded | The information is being loaded... | text`information_is_being_loaded` |
| Key | Value | Usage |
|---|---|---|
select | Select | text`select` |
search | Search | text`search` |
save | Save | text`save` |
cancel | Cancel | text`cancel` |
delete | Delete | text`delete` |
are_you_sure | Are you sure? | text`are_you_sure` |
close | Close | text`close` |
ok | OK | text`ok` |
login | Login | text`login` |
logout | Logout | text`logout` |
your_email | Your email | text`your_email` |
enter_email | Enter email address | text`enter_email` |
your_password | Your password | text`your_password` |
enter_password | Enter password | text`enter_password` |
required_field | required_field | text`required_field` |
choose_one | Choose one | text`choose_one` |
everything | Everything | text`everything` |
number_of_rows | Number of rows | text`number_of_rows` |
modal_create | New | text`modal_create` |
modal_edit | Edit | text`modal_edit` |
no_information_to_display | No information to display | text`no_information_to_display` |
information_is_being_loaded | The information is being loaded... | text`information_is_being_loaded` |
import { useLocalization } from '@jasperoosthoek/react-toolbox';
// All available default localization strings:
const DefaultStrings = () => {
const { text } = useLocalization();
return (
<div>
{/* Basic Actions */}
<div>{text`save`}</div>
<div>{text`cancel`}</div>
<div>{text`delete`}</div>
<div>{text`search`}</div>
<div>{text`select`}</div>
<div>{text`close`}</div>
<div>{text`ok`}</div>
{/* Authentication */}
<div>{text`login`}</div>
<div>{text`logout`}</div>
<div>{text`your_email`}</div>
<div>{text`enter_email`}</div>
<div>{text`your_password`}</div>
<div>{text`enter_password`}</div>
{/* Forms */}
<div>{text`required_field`}</div>
<div>{text`choose_one`}</div>
<div>{text`everything`}</div>
{/* Tables & Data */}
<div>{text`number_of_rows`}</div>
<div>{text`no_information_to_display`}</div>
<div>{text`information_is_being_loaded`}</div>
{/* Modals */}
<div>{text`modal_create`}</div>
<div>{text`modal_edit`}</div>
<div>{text`are_you_sure`}</div>
</div>
);
};
// Language support:
// - en: English (default)
// - fr: French
// - nl: Dutch
// Add custom strings:
const customStrings = {
en: { custom_key: "Custom value" },
fr: { custom_key: "Valeur personnalisée" },
nl: { custom_key: "Aangepaste waarde" }
};
const { setLocalization } = useLocalization();
setLocalization(customStrings);