React Toolbox Examples

Comprehensive examples showcasing all components and features. Each example includes working code and demonstrates real-world usage patterns.

Basic DataTable with Sorting

Simple table with column sorting functionality. Click column headers to sort data.

Column SortingCustom RenderersBadge ComponentsDefault OrderingSearch Support
IDNameEmailDepartmentStatus
4Alice Brownalice.brown@example.comMarketingactive
3Bob Johnsonbob.johnson@example.comDesignactive
5Charlie Wilsoncharlie.wilson@example.comEngineeringpending
6Diana Davisdiana.davis@example.comFinanceactive
7Eva Garciaeva.garcia@example.comEngineeringinactive
8Frank Millerfrank.miller@example.comDesignactive
9Grace Leegrace.lee@example.comHRactive
10Henry Taylorhenry.taylor@example.comEngineeringpending
11Ivy Andersonivy.anderson@example.comFinanceactive
12Jack Thompsonjack.thompson@example.comDesignactive
IDNameEmailDepartmentStatus
4Alice Brownalice.brown@example.comMarketingactive
3Bob Johnsonbob.johnson@example.comDesignactive
5Charlie Wilsoncharlie.wilson@example.comEngineeringpending
6Diana Davisdiana.davis@example.comFinanceactive
7Eva Garciaeva.garcia@example.comEngineeringinactive
8Frank Millerfrank.miller@example.comDesignactive
9Grace Leegrace.lee@example.comHRactive
10Henry Taylorhenry.taylor@example.comEngineeringpending
11Ivy Andersonivy.anderson@example.comFinanceactive
12Jack Thompsonjack.thompson@example.comDesignactive
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';
};
💡 Notes:
  • Click any column header to sort ascending/descending
  • Custom selector functions allow for complex rendering
  • Status column demonstrates Badge component integration
  • Default sorting can be set with orderByDefault prop
  • Search property enables column-specific searching

DataTable with Pagination

Table with built-in pagination controls and customizable page sizes plus sum calculations.

PaginationPage Size OptionsData FormattingLarge Dataset HandlingSum Calculations
NameEmailRoleSalaryJoin Date
John Doejohn.doe@example.comAdmin$85,000.00Jan 15, 2023
Jane Smithjane.smith@example.comDeveloper$75,000.00Mar 20, 2023
Bob Johnsonbob.johnson@example.comDesigner$70,000.00Feb 10, 2023
Alice Brownalice.brown@example.comManager$90,000.00Nov 5, 2022
Charlie Wilsoncharlie.wilson@example.comDeveloper$72,000.00Apr 12, 2023
Total$392,000.00
NameEmailRoleSalaryJoin Date
John Doejohn.doe@example.comAdmin$85,000.00Jan 15, 2023
Jane Smithjane.smith@example.comDeveloper$75,000.00Mar 20, 2023
Bob Johnsonbob.johnson@example.comDesigner$70,000.00Feb 10, 2023
Alice Brownalice.brown@example.comManager$90,000.00Nov 5, 2022
Charlie Wilsoncharlie.wilson@example.comDeveloper$72,000.00Apr 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',
  });
}
💡 Notes:
  • rowsPerPageOptions allows users to choose page size
  • null in options array means "Show All" option
  • Custom formatters (formatCurrency, formatDate) improve readability
  • Pagination automatically handles large datasets efficiently
  • showSum enables totals row with formatSum for custom formatting
  • value property specifies which field to sum for numeric columns

Editable DataTable

Interactive table with row click to edit functionality and action buttons.

Row Click EditingModal FormsAction ButtonsDelete ConfirmationReal-time Updates
NameEmailRoleStatusActions
John Doejohn.doe@example.comAdminactive
Jane Smithjane.smith@example.comDeveloperactive
Bob Johnsonbob.johnson@example.comDesigneractive
Alice Brownalice.brown@example.comManageractive
Charlie Wilsoncharlie.wilson@example.comDeveloperpending
Diana Davisdiana.davis@example.comAnalystactive
Eva Garciaeva.garcia@example.comDeveloperinactive
Frank Millerfrank.miller@example.comDesigneractive
Grace Leegrace.lee@example.comManageractive
Henry Taylorhenry.taylor@example.comDeveloperpending
NameEmailRoleStatusActions
John Doejohn.doe@example.comAdminactive
Jane Smithjane.smith@example.comDeveloperactive
Bob Johnsonbob.johnson@example.comDesigneractive
Alice Brownalice.brown@example.comManageractive
Charlie Wilsoncharlie.wilson@example.comDeveloperpending
Diana Davisdiana.davis@example.comAnalystactive
Eva Garciaeva.garcia@example.comDeveloperinactive
Frank Millerfrank.miller@example.comDesigneractive
Grace Leegrace.lee@example.comManageractive
Henry Taylorhenry.taylor@example.comDeveloperpending
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';
};
💡 Notes:
  • Click any row to open edit modal with current data
  • Action buttons provide alternative interaction method
  • DeleteConfirmButton includes built-in confirmation dialog
  • Form state automatically resets when editing different users
  • Changes are immediately reflected in the table

DataTable with Drag & Drop Reordering

Drag rows to reorder them with server persistence and error handling plus sum calculations.

Drag & DropOptimistic UpdatesError HandlingLoading StatesStock Status BadgesSum Calculations
NameCategoryPriceStockTags
Total$2,805.90
NameCategoryPriceStockTags
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);
};
💡 Notes:
  • Drag any row to reorder - changes are immediately visible
  • Optimistic updates provide instant feedback to users
  • If server save fails, the row automatically resets to original position
  • Loading indicator shows during save operation
  • Stock levels are color-coded: green (50+), yellow (20-49), red (<20)
  • showSum displays totals with custom formatting for price column

DataTable with Custom Renderers

Advanced rendering with dropdown status updates, action buttons, column filters, and sum calculations.

Custom Cell RenderersInteractive DropdownsStatus UpdatesAction ButtonsColumn FiltersSum Calculations
Order IDCustomerProductQuantityTotalActions
#1001John DoeLaptop Pro1$1,299.99
#1002Jane SmithWireless Mouse2$59.98
#1003Bob JohnsonOffice Chair1$249.99
#1004Alice BrownMonitor 27"2$659.98
#1005Charlie WilsonKeyboard Mechanical1$89.99
Total7$2,359.93
Order IDCustomerProductQuantityTotalActions
#1001John DoeLaptop Pro1$1,299.99
#1002Jane SmithWireless Mouse2$59.98
#1003Bob JohnsonOffice Chair1$249.99
#1004Alice BrownMonitor 27"2$659.98
#1005Charlie WilsonKeyboard Mechanical1$89.99
Total7$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);
};
💡 Notes:
  • Status column uses interactive dropdown for real-time updates
  • Order ID column adds # prefix for better visual formatting
  • Action buttons provide contextual operations for each row
  • optionsDropdown enables column-specific filtering
  • Multiple custom renderers can be combined in a single table
  • showSum displays totals for quantity and total columns with custom formatting

DataTable with FormModalProvider Integration

Complete CRUD operations with seamless form modal integration for create and edit operations.

Full CRUD OperationsModal FormsCreate/Edit IntegrationForm ValidationButton Integration
Employee Management
NameEmailRoleDepartmentStatusActions
John Doejohn.doe@example.comAdminEngineeringactive
Jane Smithjane.smith@example.comDeveloperEngineeringactive
Bob Johnsonbob.johnson@example.comDesignerDesignactive
Alice Brownalice.brown@example.comManagerMarketingactive
Charlie Wilsoncharlie.wilson@example.comDeveloperEngineeringpending
Employee Management
NameEmailRoleDepartmentStatusActions
John Doejohn.doe@example.comAdminEngineeringactive
Jane Smithjane.smith@example.comDeveloperEngineeringactive
Bob Johnsonbob.johnson@example.comDesignerDesignactive
Alice Brownalice.brown@example.comManagerMarketingactive
Charlie Wilsoncharlie.wilson@example.comDeveloperEngineeringpending
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';
};
💡 Notes:
  • FormModalProvider handles all form state and modal management
  • FormCreateModalButton automatically opens create modal with empty form
  • FormEditModalButton automatically populates form with selected row data
  • DeleteConfirmButton provides built-in confirmation with customizable messages
  • All operations include loading states and error handling
  • Perfect pattern for admin panels and data management interfaces
  • Copy-paste ready: includes all types, mock data, and helper functions needed

Custom Form Layout

Using FormProvider with direct component usage for maximum flexibility

FormProviderCustom LayoutValidationLoading StatesuseForm Hook
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;
💡 Notes:
  • FormProvider manages form state and validation automatically
  • Use useForm() hook to access form context in child components
  • Custom validation functions return error objects
  • Loading states are handled automatically during submission
  • FormInput, FormCheckbox and other components work seamlessly together

Modal Forms

FormModalProvider for create/edit modals with automatic state management

FormModalProviderCreate/Edit ModalsState ManagementCRUD OperationsAuto-Generated Forms
Users
John Doe - Admin
john.doe@example.com
Jane Smith - Developer
jane.smith@example.com
Bob Johnson - Designer
bob.johnson@example.com
Users
John Doe - Admin
john.doe@example.com
Jane Smith - Developer
jane.smith@example.com
Bob Johnson - Designer
bob.johnson@example.com
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,
  },
];
💡 Notes:
  • FormModalProvider automatically creates FormModal with FormFieldsRenderer
  • Form fields are automatically generated from formFields configuration
  • Include type, label, options, and formProps in field config for proper rendering
  • useFormModal() hook provides showEditModal() and showCreateModal() functions
  • No need to manually include FormModal - it's created automatically

Flexible Forms

FormProvider with FormModal integration for complex layouts and workflows

FormProvider + FormModalComplex LayoutsMulti-Column FormsConditional LogicPre-populated Data
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;
💡 Notes:
  • Combine FormProvider with FormModal for flexible form layouts
  • Use initialState prop to pre-populate forms for editing
  • Row and Col components create responsive multi-column layouts
  • Custom validation can include complex business logic
  • Perfect for contact forms, surveys, and data collection

Auto-Rendered Forms

Dynamic form rendering using FormFieldsRenderer with field configuration objects

FormFieldsRendererConfiguration-BasedMultiple Field TypesSchema-DrivenBadgeSelection
Developer Survey

Help us understand your background and preferences

ReactTypeScriptNode.jsPythonUI/UX DesignTesting
Developer Survey

Help us understand your background and preferences

ReactTypeScriptNode.jsPythonUI/UX DesignTesting
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;
💡 Notes:
  • FormFieldsRenderer automatically creates form fields from configuration
  • Use component property to specify custom form components
  • Supports all standard field types: text, number, select, textarea, checkbox
  • formProps passes additional properties to the rendered component
  • Perfect for forms generated from API schemas or CMS data

Mixed Form Approach

Combining direct components with convenience wrappers and advanced layouts

Card LayoutsConditional SectionsMixed ComponentsComplex FormsFormDropdown
Product Order Form
Customer Information
Order Details
Additional Options
Product Order Form
Customer Information
Order Details
Additional Options
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;
💡 Notes:
  • Use Card components to organize form sections logically
  • Combine different form components based on your needs
  • Conditional rendering for optional or advanced sections
  • FormDropdown provides searchable dropdown functionality
  • Perfect for complex business forms with multiple sections

All Available IconButtons

Comprehensive collection of pre-built IconButtons with loading states, variants, and sizes

30+ Pre-built IconsLoading StatesAll Bootstrap VariantsCustomizable

Click any button to toggle its loading state. All buttons support loading, different sizes, and variants.

Action Buttons
CheckButton
CloseButton
SaveButton
EditButton
DeleteButton
CopyButton
PasteButton
UnCheckButton
Create Buttons
CreateButton
CreateFolderButton
CreateSubFolderButton
CreateFileButton
Navigation Buttons
UpButton
DownButton
PlayButton
StopButton
MoveButton
SyncButton
Utility Buttons
SearchButton
DownloadButton
UploadButton
LinkButton
FlagButton
NotesButton
PencilButton
ListButton
MenuButton
CogButton
UnlockButton
ShowButton
HideButton
QuestionnaireButton
DropdownButton
ResetButton
Sort Buttons
SortButton
SortUpButton
SortDownButton

Click any button to toggle its loading state. All buttons support loading, different sizes, and variants.

Action Buttons
CheckButton
CloseButton
SaveButton
EditButton
DeleteButton
CopyButton
PasteButton
UnCheckButton
Create Buttons
CreateButton
CreateFolderButton
CreateSubFolderButton
CreateFileButton
Navigation Buttons
UpButton
DownButton
PlayButton
StopButton
MoveButton
SyncButton
Utility Buttons
SearchButton
DownloadButton
UploadButton
LinkButton
FlagButton
NotesButton
PencilButton
ListButton
MenuButton
CogButton
UnlockButton
ShowButton
HideButton
QuestionnaireButton
DropdownButton
ResetButton
Sort Buttons
SortButton
SortUpButton
SortDownButton
import React, { useState } from 'react';
import { Card, ButtonGroup } from 'react-bootstrap';
import { 
  CheckButton, SaveButton, EditButton, DeleteButton, 
  CreateButton, DownloadButton, UploadButton, 
  SearchButton, SortButton, SyncButton 
} from '@jasperoosthoek/react-toolbox';

const MyComponent = () => {
  const [loading, setLoading] = useState<boolean>(false);
  
  const handleAction = () => {
    setLoading(true);
    // Your action logic here
    setTimeout(() => setLoading(false), 2000);
  };

  return (
    <div>
      {/* Basic usage */}
      <SaveButton onClick={handleAction} loading={loading} />
      <EditButton variant="outline-primary" />
      <DeleteButton variant="outline-danger" size="sm" />
      
      {/* With custom props */}
      <CreateButton 
        variant="success" 
        disabled={loading}
        title="Create new item"
      />
      
      {/* With text */}
      <DownloadButton variant="primary">
        Download File
      </DownloadButton>
      
      {/* In button groups */}
      <ButtonGroup>
        <CheckButton />
        <EditButton />
        <DeleteButton />
      </ButtonGroup>
    </div>
  );
};

export default MyComponent;
💡 Notes:
  • All buttons support loading, disabled, and custom styling
  • Import only the buttons you need to optimize bundle size
  • Each button includes appropriate accessibility attributes
  • Compatible with all react-bootstrap Button props

Button Sizes and Variants

IconButtons support all react-bootstrap Button props including size, variant, and disabled states

Multiple SizesBootstrap VariantsLoading StatesDisabled States
Sizes
Small
Default
Large
Variants
States
Normal
Loading
Disabled
Sizes
Small
Default
Large
Variants
States
Normal
Loading
Disabled
import React, { useState } from 'react';
import { SaveButton, EditButton, CheckButton } from '@jasperoosthoek/react-toolbox';

const ButtonStatesExample = () => {
  const [loading, setLoading] = useState<boolean>(false);

  const handleAction = () => {
    setLoading(true);
    setTimeout(() => setLoading(false), 2000);
  };

  return (
    <div>
      {/* Different sizes */}
      <EditButton size="sm" />
      <EditButton /> {/* default size */}
      <EditButton size="lg" />
      
      {/* Different variants */}
      <SaveButton variant="primary" />
      <SaveButton variant="secondary" />
      <SaveButton variant="success" />
      <SaveButton variant="danger" />
      <SaveButton variant="outline-primary" />
      
      {/* Different states */}
      <CheckButton />
      <CheckButton loading={loading} onClick={handleAction} />
      <CheckButton disabled />
    </div>
  );
};

export default ButtonStatesExample;
💡 Notes:
  • All IconButtons inherit react-bootstrap Button props
  • Loading state automatically disables the button
  • Variants follow Bootstrap color scheme
  • Sizes: sm, default, lg available

Custom IconButtons

Use makeIconButton to create custom buttons with any react-icons icon

Any React IconmakeIconButton HelperFull CustomizationLoading Support
Custom Buttons
import React, { useState } from 'react';
import { makeIconButton } from '@jasperoosthoek/react-toolbox';
import { AiOutlineHeart, AiOutlineStar, AiOutlineBell } from 'react-icons/ai';
import { FiSettings, FiUser, FiMail } from 'react-icons/fi';

const MyCustomButtons = () => {
  const [favoriteLoading, setFavoriteLoading] = useState<boolean>(false);
  const [notificationLoading, setNotificationLoading] = useState<boolean>(false);
  
  // Create custom buttons using makeIconButton
  const HeartButton = makeIconButton(AiOutlineHeart);
  const StarButton = makeIconButton(AiOutlineStar);
  const BellButton = makeIconButton(AiOutlineBell);
  const SettingsButton = makeIconButton(FiSettings);
  const UserButton = makeIconButton(FiUser);
  const MailButton = makeIconButton(FiMail);

  const handleFavorite = () => {
    setFavoriteLoading(true);
    // Your favorite logic here
    setTimeout(() => setFavoriteLoading(false), 1500);
  };

  const handleNotification = () => {
    setNotificationLoading(true);
    // Your notification logic here
    setTimeout(() => setNotificationLoading(false), 1500);
  };

  return (
    <div>
      <HeartButton 
        variant="outline-danger" 
        loading={favoriteLoading}
        onClick={handleFavorite}
        title="Add to favorites"
      />
      <StarButton 
        variant="outline-warning" 
        title="Rate this item"
      />
      <BellButton 
        variant="outline-info"
        loading={notificationLoading}
        onClick={handleNotification}
        title="Toggle notifications"
      />
      <SettingsButton 
        variant="outline-secondary" 
        title="Settings"
      />
      <UserButton 
        variant="outline-primary" 
        title="User profile"
      />
      <MailButton 
        variant="outline-success" 
        title="Send email"
      />
    </div>
  );
};

export default MyCustomButtons;
💡 Notes:
  • Use makeIconButton with any icon from react-icons
  • Custom buttons inherit all IconButton functionality
  • Supports loading states, variants, and sizes
  • Perfect for brand-specific or unique icons

IconButtons with Text

IconButtons can include text alongside icons by passing children to the component

Text + IconLoading StatesFlexible LayoutAccessibility
Buttons with Text
Buttons with Text
import React, { useState } from 'react';
import { 
  SaveButton, EditButton, DeleteButton, 
  DownloadButton, UploadButton 
} from '@jasperoosthoek/react-toolbox';

const ButtonsWithText = () => {
  const [saveLoading, setSaveLoading] = useState<boolean>(false);
  const [deleteLoading, setDeleteLoading] = useState<boolean>(false);

  const handleSave = () => {
    setSaveLoading(true);
    // Your save logic here
    setTimeout(() => setSaveLoading(false), 2000);
  };

  const handleDelete = () => {
    setDeleteLoading(true);
    // Your delete logic here
    setTimeout(() => setDeleteLoading(false), 2000);
  };

  return (
    <div>
      <SaveButton 
        variant="primary" 
        loading={saveLoading}
        onClick={handleSave}
      >
        Save Document
      </SaveButton>
      
      <EditButton variant="outline-secondary">
        Edit Profile
      </EditButton>
      
      <DeleteButton 
        variant="outline-danger"
        loading={deleteLoading}
        onClick={handleDelete}
      >
        Delete Item
      </DeleteButton>
      
      <DownloadButton variant="outline-success">
        Download File
      </DownloadButton>
      
      <UploadButton variant="outline-info">
        Upload Image
      </UploadButton>
    </div>
  );
};

export default ButtonsWithText;
💡 Notes:
  • Add text by passing children to IconButton components
  • Text appears alongside the icon automatically
  • Loading states work with both icon and text
  • Maintains proper accessibility with both icon and text

IconButtons in ButtonGroups

IconButtons work seamlessly with react-bootstrap ButtonGroups and toolbars

ButtonGroup CompatibleToolbar CreationToggle StatesGrouped Actions
Editor Toolbar
Sort Controls
Sort:
Active: No sorting
Editor Toolbar
Sort Controls
Sort:
Active: No sorting
import React, { useState } from 'react';
import { ButtonGroup, Badge } from 'react-bootstrap';
import { 
  SaveButton, EditButton, CopyButton, PasteButton, DeleteButton,
  CreateButton, CreateFolderButton, CreateFileButton,
  SortButton, SortUpButton, SortDownButton 
} from '@jasperoosthoek/react-toolbox';

const ToolbarExample = () => {
  const [activeSort, setActiveSort] = useState<'none' | 'asc' | 'desc'>('none');

  const handleSort = (direction: 'asc' | 'desc') => {
    setActiveSort(direction);
  };

  const resetSort = () => {
    setActiveSort('none');
  };

  return (
    <div>
      {/* Editor Toolbar */}
      <ButtonGroup className="mb-3">
        <SaveButton title="Save" />
        <EditButton title="Edit" />
        <CopyButton title="Copy" />
        <PasteButton title="Paste" />
        <DeleteButton title="Delete" />
      </ButtonGroup>
      
      {/* Create Actions */}
      <ButtonGroup className="mb-3">
        <CreateButton title="Create" />
        <CreateFolderButton title="Create Folder" />
        <CreateFileButton title="Create File" />
      </ButtonGroup>
      
      {/* Sort Controls */}
      <div className="d-flex align-items-center gap-3">
        <span>Sort:</span>
        <ButtonGroup>
          <SortButton 
            variant={activeSort === 'none' ? 'primary' : 'outline-primary'}
            onClick={resetSort}
            title="No sorting"
          />
          <SortUpButton 
            variant={activeSort === 'asc' ? 'primary' : 'outline-primary'}
            onClick={() => handleSort('asc')}
            title="Sort ascending"
          />
          <SortDownButton 
            variant={activeSort === 'desc' ? 'primary' : 'outline-primary'}
            onClick={() => handleSort('desc')}
            title="Sort descending"
          />
        </ButtonGroup>
        <Badge bg="info">
          Active: {activeSort === 'none' ? 'No sorting' : activeSort}
        </Badge>
      </div>
    </div>
  );
};

export default ToolbarExample;
💡 Notes:
  • IconButtons integrate perfectly with ButtonGroups
  • Great for creating toolbars and action groups
  • Supports toggle states and active indicators
  • Maintains spacing and alignment automatically

UploadTextButton

Special button component for uploading and reading text files with built-in file handling

File UploadText ReadingError HandlingLoading States
File Upload
File Upload
import React, { useState } from 'react';
import { UploadTextButton } from '@jasperoosthoek/react-toolbox';

const FileUploadExample = () => {
  const [fileContent, setFileContent] = useState<string>('');
  const [fileName, setFileName] = useState<string>('');
  const [uploadLoading, setUploadLoading] = useState<boolean>(false);

  const handleFileLoad = (result: string | ArrayBuffer | null) => {
    if (typeof result === 'string') {
      setFileContent(result);
      setFileName('Uploaded file');
      setUploadLoading(false);
    }
  };

  const handleFileSelect = () => {
    setUploadLoading(true);
    setFileContent('');
    setFileName('');
  };

  const handleError = (error: any) => {
    console.error('File upload error:', error);
    setUploadLoading(false);
    alert('Error uploading file: ' + error.message);
  };

  return (
    <div>
      <UploadTextButton
        accept=".txt,.md,.json,.csv"
        onLoadFile={handleFileLoad}
        onError={handleError}
        variant="outline-primary"
        loading={uploadLoading}
        onClick={handleFileSelect}
      >
        Upload Text File
      </UploadTextButton>
      
      {fileContent && (
        <div className="mt-3">
          <h6>File Content:</h6>
          <pre 
            className="bg-light p-3 rounded" 
            style={{ maxHeight: '200px', overflow: 'auto' }}
          >
            {fileContent}
          </pre>
        </div>
      )}
    </div>
  );
};

export default FileUploadExample;
💡 Notes:
  • Automatically reads file content and returns as string
  • Supports multiple file types via accept prop
  • Built-in error handling for file operations
  • Loading states during file processing

ConfirmButton Examples

ConfirmButton provides a confirmation modal before executing actions. Perfect for operations that need user confirmation.

Modal ConfirmationCustom MessagesLoading StatesAny Button Component
Basic ConfirmButton Usage
Basic ConfirmButton Usage
import React, { useState } from 'react';
import { Alert } from 'react-bootstrap';
import { 
  ConfirmButton, SaveButton, DeleteButton, DownloadButton 
} from '@jasperoosthoek/react-toolbox';

const MyComponent = () => {
  const [saveLoading, setSaveLoading] = useState<boolean>(false);
  const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
  const [results, setResults] = useState<string[]>([]);

  const addResult = (message: string) => {
    setResults(prev => [...prev, `${new Date().toLocaleTimeString()}: ${message}`]);
  };

  const handleSave = (callback?: () => void) => {
    setSaveLoading(true);
    addResult('Save operation started...');
    
    // Perform save operation
    setTimeout(() => {
      setSaveLoading(false);
      addResult('Save operation completed successfully!');
      if (callback) callback(); // Close modal
    }, 2000);
  };

  const handleDelete = (callback?: () => void) => {
    setDeleteLoading(true);
    addResult('Delete operation started...');
    
    // Perform delete operation
    setTimeout(() => {
      setDeleteLoading(false);
      addResult('Delete operation completed!');
      if (callback) callback(); // Close modal
    }, 1500);
  };

  return (
    <div>
      <ConfirmButton
        modalTitle="Confirm Save"
        modalBody="Are you sure you want to save this document? This will overwrite any existing content."
        confirmText="Yes, Save Document"
        cancelText="Cancel"
        onConfirm={handleSave}
        loading={saveLoading}
        buttonComponent={SaveButton}
      />

      <ConfirmButton
        modalTitle="Confirm Delete"
        modalBody="This action cannot be undone. Are you sure you want to delete this item?"
        confirmText="Yes, Delete"
        cancelText="Keep It"
        onConfirm={handleDelete}
        loading={deleteLoading}
        buttonComponent={DeleteButton}
      />

      {results.length > 0 && (
        <Alert variant="info">
          <Alert.Heading>Action Results</Alert.Heading>
          <ul className="mb-0">
            {results.map((result, index) => (
              <li key={index}>{result}</li>
            ))}
          </ul>
        </Alert>
      )}
    </div>
  );
};

export default MyComponent;
💡 Notes:
  • Use onConfirm callback to handle the confirmed action
  • The callback parameter closes the modal when called
  • Loading states are automatically handled
  • Works with any button component via buttonComponent prop

DeleteConfirmButton

Specialized confirmation button for delete operations with built-in styling and messaging

Delete ConfirmationBuilt-in ModalLoading StatesVisual IndicatorsDanger Styling
Delete Items
Document 1file
Project Folderfolder
Image.jpgfile
Backup Datafolder
Delete Items
Document 1file
Project Folderfolder
Image.jpgfile
Backup Datafolder
import React, { useState } from 'react';
import { DeleteConfirmButton, FixedLoadingIndicator } from '@jasperoosthoek/react-toolbox';
import { Badge } from 'react-bootstrap';

interface Item {
  id: number;
  name: string;
  type: string;
}

const ItemList = () => {
  const [items, setItems] = useState<Item[]>([
    { id: 1, name: 'Document 1', type: 'file' },
    { id: 2, name: 'Project Folder', type: 'folder' },
    { id: 3, name: 'Image.jpg', type: 'file' },
  ]);
  const [loadingStates, setLoadingStates] = useState<{[key: number]: boolean}>({});
  const [isDeleting, setIsDeleting] = useState<boolean>(false);

  const handleDelete = (itemId: number) => {
    setLoadingStates(prev => ({ ...prev, [itemId]: true }));
    setIsDeleting(true);
    
    // Perform delete operation
    setTimeout(() => {
      setItems(items.filter(item => item.id !== itemId));
      setLoadingStates(prev => ({ ...prev, [itemId]: false }));
      setIsDeleting(false);
    }, 1500);
  };

  return (
    <div>
      <FixedLoadingIndicator 
        show={isDeleting}
        message="Deleting item..."
        variant="warning"
      />
      
      <div className="list-group">
        {items.map(item => (
          <div 
            key={item.id} 
            className="list-group-item d-flex justify-content-between align-items-center"
          >
            <div>
              <strong>{item.name}</strong>
              <Badge 
                bg={item.type === 'folder' ? 'primary' : 'secondary'} 
                className="ms-2"
              >
                {item.type}
              </Badge>
            </div>
            <DeleteConfirmButton
              onDelete={() => handleDelete(item.id)}
              loading={loadingStates[item.id]}
              size="sm"
            />
          </div>
        ))}
      </div>
    </div>
  );
};

export default ItemList;
💡 Notes:
  • Specifically designed for delete operations
  • Built-in "Are you sure?" confirmation modal
  • Automatically styled with danger variant
  • Fixed position indicator shows global delete progress
  • Perfect for item lists and data tables

Advanced ConfirmButton Patterns

Complex confirmation scenarios with custom modal content, multiple operations, and button combinations

Custom Modal ContentJSX in modalBodyButton GroupsComplex OperationsResult Tracking
Complex Operations
Button Combinations

ConfirmButton works well in button groups and toolbars:

Complex Operations
Button Combinations

ConfirmButton works well in button groups and toolbars:

import React, { useState } from 'react';
import { Alert, ButtonGroup } from 'react-bootstrap';
import { 
  ConfirmButton, DeleteConfirmButton, EditButton, SaveButton,
  MoveButton, SyncButton, CreateButton 
} from '@jasperoosthoek/react-toolbox';

interface Operation {
  loading: boolean;
  result?: string;
}

const AdvancedOperations = () => {
  const [operations, setOperations] = useState<{[key: string]: Operation}>({});

  const createOperation = (key: string) => ({
    start: () => setOperations(prev => ({ ...prev, [key]: { loading: true } })),
    complete: (result: string) => setOperations(prev => ({ 
      ...prev, 
      [key]: { loading: false, result } 
    })),
    reset: () => setOperations(prev => ({ ...prev, [key]: { loading: false } }))
  });

  const moveOperation = createOperation('move');
  const syncOperation = createOperation('sync');

  const handleMove = (callback?: () => void) => {
    moveOperation.start();
    
    // Simulate move operation
    setTimeout(() => {
      moveOperation.complete('Items moved successfully!');
      if (callback) callback();
    }, 2000);
  };

  const handleSync = (callback?: () => void) => {
    syncOperation.start();
    
    // Simulate sync operation
    setTimeout(() => {
      syncOperation.complete('Sync completed - 15 items updated');
      if (callback) callback();
    }, 3000);
  };

  const handleSave = (callback?: () => void) => {
    console.log('Save operation');
    if (callback) callback();
  };

  const handleDelete = () => {
    console.log('Delete operation confirmed');
  };

  return (
    <div>
      {/* Complex modal with custom content */}
      <ConfirmButton
        modalTitle="Move Items"
        modalBody={
          <div>
            <p>You are about to move 5 items to the archive folder.</p>
            <Alert variant="warning" className="mb-0">
              <small>This operation will take a few moments to complete.</small>
            </Alert>
          </div>
        }
        confirmText="Move Items"
        cancelText="Cancel"
        onConfirm={handleMove}
        loading={operations.move?.loading}
        buttonComponent={MoveButton}
      />
      
      {/* Sync with detailed instructions */}
      <ConfirmButton
        modalTitle="Sync Data"
        modalBody={
          <div>
            <p>This will sync all your data with the remote server.</p>
            <ul>
              <li>Upload local changes</li>
              <li>Download remote updates</li>
              <li>Resolve any conflicts</li>
            </ul>
            <Alert variant="info" className="mb-0">
              <small>Make sure you have a stable internet connection.</small>
            </Alert>
          </div>
        }
        confirmText="Start Sync"
        cancelText="Not Now"
        onConfirm={handleSync}
        loading={operations.sync?.loading}
        buttonComponent={SyncButton}
      />
      
      {/* Button groups */}
      <ButtonGroup>
        <EditButton />
        <ConfirmButton
          modalTitle="Save Changes"
          modalBody="Save all pending changes?"
          confirmText="Save"
          cancelText="Cancel"
          onConfirm={handleSave}
          buttonComponent={SaveButton}
        />
        <DeleteConfirmButton onDelete={handleDelete} />
      </ButtonGroup>

      {/* Display operation results */}
      {Object.entries(operations).map(([key, op]) => (
        op.result && (
          <Alert key={key} variant="success" className="mb-2">
            <strong>{key.charAt(0).toUpperCase() + key.slice(1)}:</strong> {op.result}
            <button 
              className="btn-close float-end" 
              onClick={() => setOperations(prev => ({ ...prev, [key]: { loading: false } }))}
              aria-label="Close"
            />
          </Alert>
        )
      ))}
    </div>
  );
};

export default AdvancedOperations;
💡 Notes:
  • modalBody can accept JSX elements for complex content
  • Perfect for operations with detailed instructions
  • Works seamlessly with ButtonGroups and toolbars
  • Can include alerts, lists, and formatted content in modals
  • Track operation results and display success messages

Basic Localization Usage

Demonstrate basic localization with built-in strings and the text\`localization_string\` pattern

Template String SyntaxBuilt-in TranslationsLanguage SwitchingDefault Strings
Language Controls
Current Language:EN
Basic String Examples
Save: Save
Cancel: Cancel
Delete: Delete
Search: Search
Are you sure?: Are you sure?
Required field: required_field
UI String Examples
Login: Login
Your email: Your email
Enter password: Enter password
Choose one: Choose one
Number of rows: Number of rows
No information: No information to display
Language Controls
Current Language:EN
Basic String Examples
Save: Save
Cancel: Cancel
Delete: Delete
Search: Search
Are you sure?: Are you sure?
Required field: required_field
UI String Examples
Login: Login
Your email: Your email
Enter password: Enter password
Choose one: Choose one
Number of rows: Number of rows
No information: No information to display
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;
💡 Notes:
  • Use text`key` syntax for clean, readable localization
  • Built-in support for English, French, and Dutch
  • Language switching updates all strings automatically
  • Over 20 common UI strings included by default

Custom Localization Strings

Add your own localization strings with support for function interpolation and parameters

Custom StringsFunction InterpolationMultiple ParametersPluralization
Custom String Examples
Language:
Simple String:
Welcome to our application!
Function with Single Parameter:
Hello, John!
Function with Number (Pluralization):
There is 1 user online
There are 5 users online
Function with Multiple Parameters:
Error: Something went wrong
Success: Operation completed
Complex Function:
Premium Plan costs $29.99
Basic Plan costs $9.99
Custom String Examples
Language:
Simple String:
Welcome to our application!
Function with Single Parameter:
Hello, John!
Function with Number (Pluralization):
There is 1 user online
There are 5 users online
Function with Multiple Parameters:
Error: Something went wrong
Success: Operation completed
Complex Function:
Premium Plan costs $29.99
Basic Plan costs $9.99
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;
💡 Notes:
  • Define custom strings with setLocalization()
  • Functions can accept multiple parameters for dynamic content
  • Perfect for pluralization and complex string formatting
  • Use textByLang() to get strings for specific languages

Form Localization

Forms automatically use localized strings for labels, placeholders, and validation messages

Form IntegrationDynamic LabelsLocalized PlaceholdersValidation Messages
Login Form
Login Form
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>
  );
};
💡 Notes:
  • Form labels and placeholders automatically update with language changes
  • Use text`key` in formFields definitions for dynamic localization
  • Validation errors can also be localized
  • Custom buttons inside forms can use localized text

DataTable Localization

DataTable components automatically use localized strings for search, pagination, and empty states

Auto LocalizationSearch PlaceholderPagination TextEmpty States
Users Table
NameEmailRoleActions
John Doejohn.doe@example.comAdmin
Jane Smithjane.smith@example.comDeveloper
Bob Johnsonbob.johnson@example.comDesigner
Users Table
NameEmailRoleActions
John Doejohn.doe@example.comAdmin
Jane Smithjane.smith@example.comDeveloper
Bob Johnsonbob.johnson@example.comDesigner
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,
  },
]
💡 Notes:
  • DataTable automatically uses localized strings for UI elements
  • Search placeholder uses text`search` string
  • Pagination uses text`number_of_rows` for row count display
  • Empty and loading states are automatically localized

Language Switcher Components

Build reusable language switcher components in various styles

Multiple StylesReusable ComponentsCurrent Language DisplayAccessible Options
Language Switcher
Language Switcher
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>
  );
};
💡 Notes:
  • Use defaultLanguages object for display names
  • Multiple UI patterns: select, buttons, dropdown
  • Always show current language state
  • Consider user preferences for language switcher placement

Complete Localization Reference

All available default localization strings and how to extend them

Default StringsMulti-language SupportReference TableExtension Guide
Default Localization Strings
EN
KeyValueUsage
selectSelecttext`select`
searchSearchtext`search`
saveSavetext`save`
cancelCanceltext`cancel`
deleteDeletetext`delete`
are_you_sureAre you sure?text`are_you_sure`
closeClosetext`close`
okOKtext`ok`
loginLogintext`login`
logoutLogouttext`logout`
your_emailYour emailtext`your_email`
enter_emailEnter email addresstext`enter_email`
your_passwordYour passwordtext`your_password`
enter_passwordEnter passwordtext`enter_password`
required_fieldrequired_fieldtext`required_field`
choose_oneChoose onetext`choose_one`
everythingEverythingtext`everything`
number_of_rowsNumber of rowstext`number_of_rows`
modal_createNewtext`modal_create`
modal_editEdittext`modal_edit`
no_information_to_displayNo information to displaytext`no_information_to_display`
information_is_being_loadedThe information is being loaded...text`information_is_being_loaded`
Default Localization Strings
EN
KeyValueUsage
selectSelecttext`select`
searchSearchtext`search`
saveSavetext`save`
cancelCanceltext`cancel`
deleteDeletetext`delete`
are_you_sureAre you sure?text`are_you_sure`
closeClosetext`close`
okOKtext`ok`
loginLogintext`login`
logoutLogouttext`logout`
your_emailYour emailtext`your_email`
enter_emailEnter email addresstext`enter_email`
your_passwordYour passwordtext`your_password`
enter_passwordEnter passwordtext`enter_password`
required_fieldrequired_fieldtext`required_field`
choose_oneChoose onetext`choose_one`
everythingEverythingtext`everything`
number_of_rowsNumber of rowstext`number_of_rows`
modal_createNewtext`modal_create`
modal_editEdittext`modal_edit`
no_information_to_displayNo information to displaytext`no_information_to_display`
information_is_being_loadedThe 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);
💡 Notes:
  • Over 20 default UI strings included out of the box
  • Support for English, French, and Dutch by default
  • Use setLocalization() to add custom strings
  • All components automatically use localized strings where appropriate