GithubHelp home page GithubHelp logo

icflorescu / mantine-datatable Goto Github PK

View Code? Open in Web Editor NEW
834.0 9.0 58.0 4.64 MB

The table component for your Mantine data-rich applications, supporting asynchronous data loading, column sorting, custom cell data rendering, context menus, nesting, Gmail-style batch row selection, dark theme, and more.

Home Page: https://icflorescu.github.io/mantine-datatable/

License: MIT License

JavaScript 0.68% TypeScript 91.06% CSS 8.25% HTML 0.01%
datagrid datatable mantine react typescript ui javascript dark-mode dark-theme uikit

mantine-datatable's Introduction

Mantine DataTable

Publish NPM & deploy docs workflow
NPM version License Stars Last commit Closed issues Downloads Language Sponsor the author

The lightweight, dependency-free, dark-theme aware table component for your Mantine UI data-rich applications, featuring asynchronous data loading support, pagination, intuitive Gmail-style additive batch rows selection, column sorting, custom cell data rendering, row expansion, nesting, context menus, and much more.

Mantine DataTable

⚠️ Mantine DataTable V7 is compatible with Mantine V7.
πŸ’‘ If you're looking for the old version that works with Mantine V6, head over to Mantine DataTable V6.

Features

Trusted by the community

Emil Sorensen @ kapa.ai:

Mantine DataTable is a great component that’s core to our web app - it saves us a ton of time and comes with great styling and features out of the box

Giovambattista Fazioli @ Namecheap (@gfazioli is also a valuable Mantine DataTable contributor):

Thank you for the wonderful, useful, and beautiful DataTable that has allowed me to create several applications without any problem πŸ‘

Mantine DataTable is used by developers and companies around the world, such as: SegmentX, Namecheap, EasyWP, Aquarino, Dera, kapa.ai, exdatis.ai, teachfloor, MARKUP, BookieBase, zipline, Pachtop, Ganymede, COH3 Stats, Culver City Rental Registry and many more.

If you're using Mantine DataTable in your project, please drop me a line at the email address listed in my GitHub profile and I'll be happy to add it to the list and on the documentation website.

Full documentation and examples

Visit icflorescu.github.io/mantine-datatable to view the full documentation and learn how to use it by browsing a comprehensive list of examples.

Quickstart

Create a new application with Mantine, make sure to have the clsx peer dependency installed, then install the package with npm i mantine-datatable or yarn add mantine-datatable.

Import the necessary CSS files:

import '@mantine/core/styles.layer.css';
import 'mantine-datatable/styles.layer.css';
import './layout.css';

Make sure to apply the styles in the correct order:

/* layout.css */
/* πŸ‘‡ Apply Mantine core styles first, DataTable styles second */
@layer mantine, mantine-datatable;

Use the component in your code:

'use client';

import { Box } from '@mantine/core';
import { showNotification } from '@mantine/notifications';
import { DataTable } from 'mantine-datatable';

export function GettingStartedExample() {
  return (
    <DataTable
      withTableBorder
      borderRadius="sm"
      withColumnBorders
      striped
      highlightOnHover
      // πŸ‘‡ provide data
      records={[
        { id: 1, name: 'Joe Biden', bornIn: 1942, party: 'Democratic' },
        // more records...
      ]}
      // πŸ‘‡ define columns
      columns={[
        {
          accessor: 'id',
          // πŸ‘‡ this column has a custom title
          title: '#',
          // πŸ‘‡ right-align column
          textAlign: 'right',
        },
        { accessor: 'name' },
        {
          accessor: 'party',
          // πŸ‘‡ this column has custom cell data rendering
          render: ({ party }) => (
            <Box fw={700} c={party === 'Democratic' ? 'blue' : 'red'}>
              {party.slice(0, 3).toUpperCase()}
            </Box>
          ),
        },
        { accessor: 'bornIn' },
      ]}
      // πŸ‘‡ execute this callback when a row is clicked
      onRowClick={({ record: { name, party, bornIn } }) =>
        showNotification({
          title: `Clicked on ${name}`,
          message: `You clicked on ${name}, a ${party.toLowerCase()} president born in ${bornIn}`,
          withBorder: true,
        })
      }
    />
  );
}

Make sure to browse the comprehensive list of usage examples to learn how to unleash the full power of Mantine DataTable.

Other useful resources

Mantine DataTable works perfectly with Mantine Context Menu, a library built by the same author that enables you to enhance your UIs with desktop-grade, lightweight yet fully-featured context menus that respect the Mantine color scheme out of the box:

Mantine ContextMenu

Contributing

See the contributing guide in the documentation website or the repo CONTRIBUTING.md file for details.

Here's the list of people who have already contributed to Mantine DataTable:

Contributors list

Want to become a code contributor?

Support the project

If you find this package useful, please consider ❀️ sponsoring my work.
Your sponsorship will help me dedicate more time to maintaining the project and will encourage me to add new features and fix existing bugs.
If you're a company using Mantine, Mantine DataTable or Mantine ContextMenu in a commercial project, you can also hire my services.

Other means of support

If you can't afford to sponsor the project or hire my services, there are other ways you can support my work:

The more stars this repository gets, the more visibility it gains among the Mantine users community. The more users it gets, the more chances that some of those users will become active code contributors willing to put their effort into bringing new features to life and/or fixing bugs.

As the repository gain awareness, my chances of getting hired to work on Mantine-based projects will increase, which in turn will help maintain my vested interest in keeping the project alive.

Hiring the author

If you want to hire my services, don’t hesitate to drop me a line at the email address listed in my GitHub profile. I’m currently getting a constant flow of approaches, some of them relevant, others not so relevant. Mentioning β€œMantine DataTable” in your text would help me prioritize your message.

Acknowledgements

πŸ™ Special thanks to Ani Ravi for being the first person to sponsor my work on this project! πŸ’• Additional thanks to all sponsors!

License

The MIT License.

mantine-datatable's People

Contributors

abdullahahmeda avatar alexcastrodev avatar arperry avatar blentz100 avatar enesusta avatar gfazioli avatar icflorescu avatar irflorescu avatar matthijsmud avatar otobot1 avatar sajarin-m avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mantine-datatable's Issues

Expanded rows should be controllable

As requested here.

Gist:

The rowExpansion property object should also include:

  • records β†’ currently expanded records
  • onChange β†’ callback fired when currently expanded records change: onChange: (records: T[]) => void

Wrong module file extension in package.json

Describe the bug
In package.js, the module is defined as "module": "dist/index.ejs", but the build.mjs generates a file with the mjs extension.

Expected behavior
package.json should be switch to use index.mjs

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
I discovered this issue while using the package with Vite, and Vite complained about an incorrect module export, and indeed it was point to a non-existing file.

rowExpansion bug: All rows expand

Describe the bug
In the rowExpansion feature...

If any/all records have a field name that starts with a capital letter, clicking on any row causes all rows to expand.

For instance:
const rows = [{ID: 123, "First Name": "Danny"}, {ID: 789, "First Name": "Eiter"}] causes all records to expand instead of the single row the user clicks.

A temporary workaround is to do the following:
const rows = [{id: 123, firstName: "Danny"}, {id: 789, firstName: "Eiter"}]

To Reproduce
Steps to reproduce the behavior:

  1. Create a DataTable using the rows example I showed above.
  2. In the UI, expand the first row.
  3. All rows will expand.

Expected behavior
Only one row should expand.

Screenshots
N/A

Desktop (please complete the following information):

  • OS: macOS
  • Browser Chrome
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
TypeScript, NextJS

Improve source code readability

Source code readability could use some improvements in a few places.
Quote from Reddit:

It might just be my old eyes, but I found a few of your files somewhat hard to parse. As an example, did this section, which passes a prop to DataTableRow need to be a ternary-if-block-hybrid?

 onSelectionChange={
    onSelectedRecordsChange
      ? (e) => {
          if ((e.nativeEvent as PointerEvent).shiftKey && lastSelectionChangeIndex !== null) {
            const recordsInterval = records.filter(
              recordIndex > lastSelectionChangeIndex
                ? (_, index) => index >= lastSelectionChangeIndex && index <= recordIndex
                : (_, index) => index >= recordIndex && index <= lastSelectionChangeIndex
            );
            onSelectedRecordsChange(
              selected
                ? differenceBy(selectedRecords, recordsInterval, (r) => getValueAtPath(r, idAccessor))
                : uniqBy([...selectedRecords, ...recordsInterval], (r) =>
                    getValueAtPath(r, idAccessor)
                  )
            );
          } else {
            onSelectedRecordsChange(
              selected
                ? selectedRecords.filter((record) => getValueAtPath(record, idAccessor) !== recordId)
                : uniqBy([...selectedRecords, record], (record) => getValueAtPath(record, idAccessor))
            );
          }
          setLastSelectionChangeIndex(recordIndex);
        }
      : undefined
    } 

Totally agree. As a general rule of thumb, we shouldn't sacrifice readability in favor of efficiency.

Modifying record data from a column

I am trying to implement an inline-editing solution using this component. I am trying to edit the record data directly using an input component as a column, and it's onChange event to manipulate the record data as follows.

                columns={[
                    {
                        accessor: 'name',
                        title: 'Name',
                        sortable: true,
                        render: ({ name }) => (
                            <TextInput
                                defaultValue={name}
                                onChange={(event) => {
                                    name = event.currentTarget.value;
                                    console.log(name);
                                }}
                            />
                        ),
                    },

However, record data doesn't get updated.

                    {
                          key: 'save',
                          color: 'green',
                          title: 'Speichern',
                          icon: <IconDeviceFloppy size={18} />,
                          onClick: () => {
                              console.log(record.name);
                          },
                      },

Any suggestions?

Sort by date

Is your feature request related to a problem? Please describe.
When using sortable: true, on a column with dates, dates are sorted wrongly

Describe the solution you'd like
A way to sort by date.

Here's a screenshot from my test with Mantine data table.

CleanShot 2022-09-17 at 11 46 00@2x

As you can see the date column is sorted wrongly. The underlying data is a string like date: "21/09/2022", I guess I should transform those to something that javascript can sort. But I don't really know how I would combine that with mantine-datatable.

pass column to onRowClick

Is your feature request related to a problem? Please describe.
When using onRowClick, the event fired when we click on every column of the row. If we don't want the rowClick fired on some column, we have no idea to do that.

Describe the solution you'd like
If we can pass column clicked to onRowClick that would be solved the issue.

onRowClick: (data, column) => {
   // check which column we clicked on row
   // do row click
}

Add a changelog

We already have a lot of new features, so keeping a changelog would be a good idea...

First Column of Table Missing bottom border

Describe the bug
If you look at the pagination example, you'll notice that the first column is missing a bottom border:
image

I'm able to reproduce this locally as well with a new table.

Was this intended? I originally assumed it was due to default sorting, but the first column does not look to be sorted in the pagination example.

Custom Render Overlap with Row Selection

Describe the bug
When using a custom render function, items will overlap the row selection box when scrolled to the right on the table.

To Reproduce

  1. Enable row selection on table
  2. Add custom render function with an element instead of text
    render: () => (<Avatar>BM</Avatar>)

Screenshots

Top has z-index: 1 on the row selection box
image

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser Chrome
  • Version 105.0.5195.102

Additional context
Adding z-index: 1 to the row selection box appears to fix the issue.

Typo in README

Should be "multiple rows selection" instead of "multple rows selection".
PR on the way.

don't override paginationTextValue if provided

Describe the bug
My custom paginationTextValue gets overridden if totalRecords is 0

To Reproduce
Add a custom paginationTextValue
remove all items
with no items paginationTextValue gets replaced with ...

Column titleClassName support

Is your feature request related to a problem? Please describe.
We can styling column cells, but we can't styling column header/title cells.

Describe the solution you'd like
We can do the same like cellsClassName, cellsStyle

      columns={[
        {
          // style title with a class name
          titleClassName: classes.idColumnTitle,
          // style header with a CSS properties object
          titleStyle: {
            fontStyle: 'italic',
          },
        },
        ...
      ]}

Add a display rows per page dropdown or textbox with pagination

Is your feature request related to a problem? Please describe.
It would be nice to add a dropdown to select how many rows user wants to show per page like this
image

Describe the solution you'd like
I think the prop recordPerPage should show the dropdown so that both dropdown and page info can be sync

Describe alternatives you've considered
An alternative can be to add a withLimitDropdown prop to table which if it is true it should show the limit dropdown and get the value from recordsPerPage state

<DataTable
  recordsPerPage="10"
  withLimitDropdown
/>

Records With Custom Types Lead To TypeScript Error

Discussed in #29

This issue came to my attention while I was making silly mistakes as mentioned in the linked discussion. However, I eventually got this code to work, but the TypeScript error that I had been investigating turned out to be a read herring - the table renders just fine.

function modTable() => {
    const modStates: modForTable[] = useAppSelector(selectModsForTable);

    return (
        <DataTable
            records={modStates}
            columns={[
                { accessor: "name"},
                { accessor: "mapCount" },
                { accessor: "type" },
                { accessor: "communityRatings.quality" },
                { accessor: "communityRatings.difficulty" },
                { accessor: "tech" },
                { accessor: "cmlDifficulty" },
                { accessor: "reviews" },
            ]}
        />
    );
}


interface modForTable {
    id: number,
    name: string,
    mapCount: number,
    type: string,
    communityRatings: {
        quality: string,
        difficulty: string,
    },
    tech: string,
    cmlDifficulty: string,
    reviews: string,
}
```</div>


![image](https://user-images.githubusercontent.com/27628434/189811260-2fb284fe-f796-43b4-91e7-a8185ee98f18.png)

Having Extra line on Table

Screen Shot 2022-10-03 at 8 24 52 PM

            <DataTable
              minHeight={150}
              withBorder
              columns={[
                { accessor: 'name', width: 100 },
                { accessor: 'streetAddress', width: 100 },
                { accessor: 'city', width: 100 },
                { accessor: 'state', width: 100 },
              ]}
              // records={records}
              records={[]}
              totalRecords={companies.length}
              recordsPerPage={PAGE_SIZE}
              page={page}
              onPageChange={(p) => setPage(p)}
              noRecordsText="No records to show"
              sx={{
                marginRight: 50,
                borderRadius: 5,
              }}
            />

Make row actions cell sticky

Is your feature request related to a problem? Please describe.
Make row actions cell sticky like the first checkbox cell.

image

Describe the solution you'd like
Add sticky property to column properties

        accessor: 'actions',
        title: <Text mr="xs">Row actions</Text>,
        textAlignment: 'right',
        sticky: true,

Unable to select row text with row selection enabled.

Describe the bug
Enabling row selection results in column text being unselectable.

To Reproduce
Steps to reproduce the behavior:

  1. Enable row selection on a table
  2. Try to select text in the table

Expected behavior
Text to be selectable with row selection.

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Chrome
  • Version: 104.0.5112.102

Additional context
It seems like maybe clicking a row would select the whole row, but nothing happens instead. Being able to still select text would be extremely useful.

Row inline edits

Is your feature request related to a problem? Please describe.
The DataTable component does not support inline row edits. Inline edits are more desirable for enterprise-based applications. We can currently use the render props for each field separately. This is a length and code repetition that cannot be avoided. We always need to find an index to edit a row and update the state based on the current implementation.

Describe the solution you'd like
I would like to request a pattern where we can provide a RowComponent that implements the conditional logic if the row is being edited and renders the editable Row otherwise renders the default UI. It will be also best if we can get the row indexes as well with all event handlers so that we do not always iterate over the rows to find indexes.

Describe alternatives you've considered
Currently using render props to render editable UI vs Fixed UI.

Provide Feedback On Initially Expanded Rows To Parent Component

I've run into a bit of a problem using the row expansion feature in my own React SPA. Each of the records I'm passing to the table have an id, and I'm using react-router-dom to change the url as I expand and collapse rows. The base url is /mods and if a row is expanded then the url is /mods/:recordID. This is mostly working, but I haven't been able to handle the case where someone loads the page with an id in the url that doesn't exist. I'd like the router to navigate to /mods, but I can't think of a good way to do this that doesn't involve going through all of the records myself.

Instead of duplicating the logic inside of the table, I propose allowing the parent to pass in a callback function that will be called after the rows are initially expanded. The callback function would be passed an array of records that had been expanded by the function passed to initiallyExpanded. This would allow the parent to react to cases where nothing expanded, and other cases, without forcing them to execute the initiallyExpanded function against the records for a second time outside of the table.

I'm happy to take on the implementation of this, but I welcome feedback on the idea and potentially better ways of solving the problem.

Pagination bar not responsive friendly and disappeared in horizontal scroll

Describe the bug
The pagination bar is not sticky and adjust to screen width when added more column added / screen size change and horizontal scroll shown.
image
needed to do horizontal scroll to the end of the table
image

To Reproduce
Steps to reproduce the behavior:

  1. Zoom out the screen/ add more column to datatable to make it horizontal scroll

Expected behavior
A clear and concise description of what you expected to happen.
Should be like this, the pagination bar is not effect by the screen size and column count
image

Try to get rid of lodash peer dependency

Mantine DataTable is using some utility functions from lodash and bundling it would be crazy, thus the peer dependency. However, as somebody kindly pointed out on Mantine's Discord channel, there are some compatibility issues with lodash & Vite.

Maybe we could simply replace the functions we're using and get rid of lodash altogether?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.