Skip to content

A react.js datatable, built to work out of the box but also be customisable with little effort.

Notifications You must be signed in to change notification settings

JoshBot-Debug/datatable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React Datatable

The styling of the datatable can be customized using CSS.

Check out the DEMO WEBSITE

A datatable equiped with every commonly used filter. The demo has an array of 1,000 records. Not all features are active here. If you find a bug or want a feature, raise an issue on GitHub.

☕ Support My Work

Hey there! 👋 If my npm libraries have made your coding journey easier or sparked creativity, consider supporting my work with a virtual coffee. Your generosity keeps the code flowing and inspires more innovations! ☕🚀

"Buy Me A Coffee"

Quick Features

  • Sorting
  • Multi Sorting
  • Number filter
  • Text filter
  • Boolean filter
  • Set filter
  • Pagination
  • Toggleable columns
  • A Seperate controller from component, to allow customization.
  • Added client sided data manipulation
  • Editable cells
  • Cell validation on edit

Example usage

To import styles you need to add this to the top

You can copy the contents of this css file and customize it to suit your theme

import "@jjmyers/datatable/build/styles/default.css"
import { useDatatable, type Datatable } from "@jjmyers/datatable";
import "@jjmyers/datatable/build/styles/default.css" // OR elegance.css

const status = ["online", "offline", "available", "unavailable", "dnd"]

type Data = {
  id: number;
  status: string;
  fullName: string;
  // ...more fields
}


function MyListOfData() {

  const [isFetching, setIsFetching] = useState(false);

  const onSaveChanges = (dirtyRows: Data[]) => new Promise((resolve) => {
    console.log({ dirtyRows })
    setTimeout(() => resolve(true), 3000)
  })

  const { Datatable, ...controller } = useDatatable<Data>({
    data: data,         // An array of objects
    count: data.length, // This is the total number of records in the database
    serverSide: false,  // If this is false, data manipulation will be handled client sided. DEFAULT: true
    onFilter: console.log, // If serverSide is true, you need to handle the filters here and update data.
    onSaveChanges: onSaveChanges,
    validateChanges: {
      lastName: (value, field, dirtyRow, columns, originalRow) => {
        if (!value) return null;
        if (value.length > 3) return "Max 3 characters"
        if (value === dirtyRow.middleName || value === originalRow?.middleName) return "Middle name and lastname cannot be the same"
        return null
      },
      // A special field in validateChanges, used to perform validation on all fields, regardless wheather they were edited or not.
      // If any field in the row is edited, all fields in that row will go through this validator.
      // A good place to check for required fields if the data comes in empty and on edit you need to make sure the fields were filled.
      __allRows__: (value, field, dirtyRow, columns, originalRow) => {
        if (!value && field === "firstName") return "First name is required"
        if(value && field === "firstName" && value.length < 2)  return "Minimum 2 characters is required"
        // Check all other fields...
        return null
      },
    },
    initialSortOrder: {
      id: { orderIndex: 1, sortDirection: "desc" }
    },
    columns: [
      // There are more props
      // You'll have to check them yourself
      { field: "id", width: 85, datatype: "number", editable: false },
      { field: "status", editable: val => val !== "dnd" setOptions: status, multiFilter: true },
      { field: "fullName", editable: false, width: 250 },
      { field: "firstName" },
      { field: "middleName" },
      { field: "lastName" },
      { field: "email", width: 250, datatype: "email", sortable: false, filterable: false },
      { field: "phone", datatype: "phone" },
      { field: "isActive", datatype: "boolean" },
      { field: "profileImage", datatype: "image", omit: true },
      { field: "website", width: 250, datatype: "link" },
      { field: "loginTime", datatype: "time" },
      { field: "dateOfBirth", width: 180, datatype: "date" },
      { field: "about", width: 500, datatype: "paragraph" },
      { field: "createdAt", width: 250, datatype: "datetime" },
      { field: "customField" },
    ],
  })
  
  // Just an example of how you can add buttons here and manipulate the datatable if needed.
  const AppsPanel = ({ OmitColumns }: Datatable.AppsPanelProps) => (
    <>
      <button className="elegance-button" onClick={() => controller.reset(true)} style={{ padding: 8 }}>Reset Filters</button>
      <button className="elegance-button" onClick={() => controller.reset()} style={{ padding: 8 }}>Clear Filters</button>
      {OmitColumns}
    </>
  )

  // Just an exmple of adding options to rows
  const RowOptionMenu = ({ row, rowIndex }: Datatable.RowOptionMenuProps<Data>) => (
    <>
      <button className="elegance-button" onClick={() => setIsFetching(true)} style={{ padding: 8 }}>Fetching On</button>
      <button className="elegance-button" onClick={() => setIsFetching(false)} style={{ padding: 8 }}>Fetching Off</button>
    </>
  );


  return (
    <Datatable
      isFetching={isFetching}
      RowOptionMenu={RowOptionMenu}
      AppsPanel={AppsPanel}

      // If this is not passed, select option will go, otherwise it uses this fn to determine if a row is selectable
      isSelectable={row => row.is_active}

      // Sometimes we want the row options to show when you click on a row, mostly when you have many columns and have to scroll to click options.
      showOptionsOnRowClick

      // To auto-size the column
      columnNameFontSize={16}
      {...controller}
    />
  )

}

Releases

No releases published

Packages

No packages published