How to control ReactJS MUI table column height and width - reactjs

Recently I used ReactJS MUI Table component, but I feel it's height is too large for my project nature. I am unable to properly control cell width and height of MUI Table component. Please anyone help me.

There are a few ways to customize your tables in Material UI. This page goes over the recommended ways in detail.
For tables you can add size='small' to your <TableCell> components make your table cells smaller. Or to make the table extremely dense, you can add padding='none' to your <TableCell> components.
<TableCell size='small'>
More specifics about Material UI Tables can be found here.

Related

React MUI - is it possible to place a component / div (a chart for example) inside a Table Cell?

I'm using React MUI, and I'd like to place a component (a chart for example) inside a Table Cell.
Is it possible?
Yes you can place any node in MUI Table cell like this:
<TableCell>
<div>
...
</div>
</TableCell>
I didn't try with charts, but I was able to place barcode, so it should be matter of adjusting and styling.

Infinite loading with react-table + react-virtualized / react-window

I have the following requirements to my table:
Table should have fixed header
It needs to autosize: for infinite scroll to work the first fetch should get sufficient amount of data for scroll to appear at all.
table body should work as infinite loader: when scrolled to the end of the list table body should show loading indicator and load more rows
My assumptions are as follows:
as user will scroll through possibly large sets of data I should virtualize lists (react-virtualized seems to be the only good option for me)
as we currently have react-table I want to keep it (it has great mechanism of declaring table rows, columns, accessing data and filtering + sorting)
As we use material ui I need to use material ui react components
Because react-virtualized has own Table component I could use it, but react-table has different way of rendering rows and columns, therefore I have to use List component. (react-table separates rows and columns while react-virtualized uses columns directly as children of Table component)
I saw that react-virtualized works with HOC component called InfiniteLoader, so I should use that as well
Finally I need my columns to not be messed up just because it has more text (i.e. have dynamic height). So I tried to use CellMeasurer for this.
What I was able to achieve can be seen in this sandbox
https://codesandbox.io/s/react-table-infinite-mzkkp?file=/src/MuiTable.js
(I cannot provide code here because it is quite large)
So, in general I could make Autosizer, CellMeasurer and List components from react-virtualized to work.
I am stuck at inifinite scroll part. I saw the example on official docs, but it seems to be a little bit anti pattern (mutation state directly is not a good thing at all)
So I tried to achieve similar result, however if you could see, my loadMore function fires too early for some reason. It leads to requests being sent on nearly every scroll event.
Any help is much appreciated.
What I tried already:
Using react-window instead of react-virtualized
It works only for simple use cases, and fails with dynamic size of cells.
Using react-inifnite-scrollcomponent (https://www.npmjs.com/package/react-infinite-scroll-component)
It is working for entire page (unable to make "sticky" header, unable to render loading indicators as part of table body, it odes not have any optimization for long lists)
Using Table component from react-virtualized.
I was unable to make it work with react-table (as Table component from react-virtualized seems to render Cells directly as children of Table component. I know it has renderRow function, but it means two separate places while react-table has
<TableRow
{...row.getRowProps({
style
})}
component="div"
>
{row.cells.map((cell) => {
return (
<TableCell {...cell.getCellProps()} component="div">
{cell.render("Cell")}
</TableCell>
);
})}
</TableRow>
Also, it is not clear how to render custom filters this way.
I know this is not the answer you were looking for, but I recommend using an IntersectionObserver instead of the virtualize library. react-virtualized is not great for dynamic/responsive sized elements. IntersectionObserver is a native browser api that can detect when an element enters the viewport, without providing it with element sizes.
You can easily use it with a react library like react-intersection-observer which has an InView component and a useInView hook, though that would require wrapping every table cell with InView. The performance of an IntersectionObserver tends to be better than a scroll event-based solution like react-virtualized, though that might degrade if you have 1000s of observers.
You could also use something like intersection-observer-admin, which will pool all your observers into one instance similar to the react SyntheticEvent. You'd want to integrate that into something like React.useContext or redux.
I've found the Virtuso package to be a great help for this. Works better out the box for dynamically sized list items.
I don't have a complete solution for you, but here are a few things that might help you in your quest:
Consider a static header instead of using position: sticky to keep the header row at the top.
(If you could get everything else in
react-inifnite-scrollcomponent to work, this would solve the sticky
header problem.)
A method I've used is to adjust for the size of the scrollbar and always include it (even if not needed) - this may or may not work in all cases:
// Header div
<div
style={{ width: 'calc(100% - 0.9em)' }} // accomodate for the width of the scrollbar
>
// header stuff
</div>
// list (simplified for clarity) - here I used react-window
<div>
<AutoSizer>
{({ height, width }) => (
<List
style={{
overflowX: 'hidden',
overflowY: 'scroll', // always display scrollbar
}}
>
{RenderRow} // function to return a complete react-table row
</List>
)}
</AutoSizer>
</div>
And here are some other ideas if that one doesn't work for you:
https://stackoverflow.com/a/63412885/6451307.
If you need horizontal scrolling, you might consider the above plus a wrapper to provide the horizontal scrolling separately.
Consider the table as a list of rows for virtualization purposes.
It sounds like you've already tried this some, but I definitely found it easiest to use the list virtualization tools and then render a row of cells for each list item.
You can see an example of that in my code above, too.
Consider an overlay for the loading indicator.
If it works with your UI needs, create a separate element for the loading indicator that overlays the table body (using absolute positioning and turning it on only when it's needed). It could be solid to hide the table data completely or have a translucent background. This would prevent it from causing problems with whatever is going on in the table/list itself.
(Some accessibility actions might need to be taken, too. Like hiding the table data from screen readers when the overlay is up, giving the overlay role="alert" or similar, etc. so consider that if you go this route.)
If you're not already doing it, consider using div's instead of trying to use table elements to allow for easier styling and more flexible element structure.
react-table adds the correct table roles so you can use div's and your table should still have the correct semantics as long as you apply the react-table functions properly - like {...getTableBodyProps()} and similar.
Hopefully, one or more of those will help you get closer to your goal. Good luck!

Want to Create Pagination on table from Material UI in React Application

I am creating a table with data. Want pagination like this attached image in the footer.
Left-hand side I want the numbers and right-hand side Results per page.
Probably you have to use the combination of Pagination and Table pagination. And hide the unused panels with the CSS.
<div className={classes.root}>
<Pagination count={10} variant="outlined" shape="rounded" />
<TablePagination
component="div"
count={100}
page={page}
onChangePage={handleChangePage}
rowsPerPage={rowsPerPage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</div>;
I have created a sample codesandbox (This is just a workaround) - https://codesandbox.io/s/material-demo-forked-wmm4z?file=/demo.tsx:891-1225
Let me know if you need more help.
As #Tejogol mentioned you can use the Material UI table example pagination and change it.
You can store the current page number in a state variable and add a different style to the corresponding navigation field. The style seems like a simple border with a small border radius (1-3px).
For the results per page you can use React spacers. Don't forget to update the current page number when changing the results per page.

Creating a table that can drag and drop both columns and rows on React

I want to create a table that can drag and drop both columns and rows on React. I've look at other solutions like react-beautiful-dnd, table-dragger, etc. The best one I've found so far is ag Grid but that would require me to get the license. I have been looking for other solutions out there and even trying to build this functionality myself in React. Does anyone have an insight on how to implement this functionality or even recommend other solutions that could help achieve this functionality.
There are different packages that you can use for this purpose that are open-source. No need to implement it yourself. Some examples that are worth looking into:
react-table-hoc-draggable-columns
react-sortable-hoc
material-table
dnd-kit helped me achieve column and row dragging. The trick was enabling column OR row dragging only when each is needed. It seems unlikely a UI would need a column and a row to drag simultaneously. So in my case if I hover on a column header dnd-kit uses horizontal dragging settings but if I hover on a row "header" then dnd-kit uses vertical dragging settings. That makes it appear like they can both happen when really it's one at a time.
Here are some relevant lines of example code to get started.
const [columnHover,setColumnHover] = React.useState(false);
<DndContext
modifiers={[columnHover ? restrictToHorizontalAxis : restrictToVerticalAxis]}
>
<SortableContext
items={columnHover ? columnIDs : rowIDs}
strategy={columnHover ? horizontalListSortingStrategy : verticalListSortingStrategy}
>
...
</SortableContext>
</DndContext>

Material-table for react

I use material-ui for my project. And for data tables I use material-table. material-ui basic table has prop "stickyHeader" which fixes the table header while scrolling table body. I need the same thing for material-table but I can not find anything like it.
I tried to do it with custom css but my table becomes dependant on the layout. Is there any simple solution to have fixed footer and header for my material-table ?
You can use options.maxBodyHeight to make material-table sticky header. But there is no solution for fixed footer for now.
options={{
maxBodyHeight: 200
}}

Resources