I am trying to make react table scrollable horizontally and vertically but right now it is taking all the space according to the data. I want to make this table of fixed height and scrollable in both direction.
Table component:
import React from "react";
import { useTable } from "react-table";
const Table = ({ columns, data }) => {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({
columns,
data,
});
return (
<table {...getTableProps()} className="text-center">
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th
className="bg-primary-dark text-white p-4 text-center"
{...column.getHeaderProps()}
>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody
{...getTableBodyProps()}
className="bg-primary-light text-primary-dark overflow-scroll"
>
{rows.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>;
})}
</tr>
);
})}
</tbody>
</table>
);
};
export default Table;
Table Container
import React, { useMemo } from "react";
import useData from "../../hooks/useData";
import Table from "./Table";
const TableSection = React.memo(({ query }) => {
const { data, runtime, error } = useData(query);
const column =
data.length > 0 &&
Object.keys(data[0]).map((key) => {
return {
Header: data[0][key],
accessor: key,
};
});
const columns = useMemo(() => column, [column]);
const queryData = useMemo(() => data.slice(1), [data]);
return (
<div className="col-start-2 col-end-3 row-start-3 row-end-4 text-white m-6">
<Table columns={columns} data={queryData} />
</div>
);
});
export default TableSection;
Anyone please help me with this.
CodePudding user response:
Define the style on the container you want to be fixed-height and scrollable.
maxHeight: "30rem",
overflow: "auto",
CodePudding user response:
You can't make the body scrollable with your markup, you have to use div
tag instead of table
tag and in order to make the table scrollable have to use the properties overflow-y
and overflow-x
to be applied to your div body
:
.tbody {
${"" /* These styles are required for a scrollable table body */}
overflow-y: scroll;
overflow-x: scroll;
height: 250px;
}
Component Table:
import React from "react";
import styled from "styled-components";
import {
useTable,
useResizeColumns,
useFlexLayout,
useRowSelect
} from "react-table";
import makeData from "./makeData";
const Styles = styled.div`
padding: 1rem;
${"" /* These styles are suggested for the table fill all available space in its containing element */}
display: block;
${"" /* These styles are required for a horizontaly scrollable table overflow */}
overflow: auto;
.table {
border-spacing: 0;
border: 1px solid black;
.thead {
${"" /* These styles are required for a scrollable body to align with the header properly */}
overflow-y: auto;
overflow-x: hidden;
}
.tbody {
${"" /* These styles are required for a scrollable table body */}
overflow-y: scroll;
overflow-x: scroll;
height: 250px;
}
.tr {
:last-child {
.td {
border-bottom: 0;
}
}
border-bottom: 1px solid black;
}
.th,
.td {
margin: 0;
padding: 0.5rem;
border-right: 1px solid black;
${"" /* In this example we use an absolutely position resizer,
so this is required. */}
position: relative;
:last-child {
border-right: 0;
}
}
}
`;
const headerProps = (props, { column }) => getStyles(props, column.align);
const cellProps = (props, { cell }) => getStyles(props, cell.column.align);
const getStyles = (props, align = "left") => [
props,
{
style: {
justifyContent: align === "right" ? "flex-end" : "flex-start",
alignItems: "flex-start",
display: "flex"
}
}
];
function Table({ columns, data }) {
const defaultColumn = React.useMemo(
() => ({
// When using the useFlexLayout:
minWidth: 30, // minWidth is only used as a limit for resizing
width: 150, // width is used for both the flex-basis and flex-grow
maxWidth: 200 // maxWidth is only used as a limit for resizing
}),
[]
);
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
{
columns,
data,
defaultColumn
},
useResizeColumns,
useFlexLayout,
useRowSelect,
(hooks) => {
hooks.allColumns.push((columns) => [
// Let's make a column for selection
...columns
]);
hooks.useInstanceBeforeDimensions.push(({ headerGroups }) => {
// fix the parent group of the selection button to not be resizable
const selectionGroupHeader = headerGroups[0].headers[0];
selectionGroupHeader.canResize = false;
});
}
);
return (
<div {...getTableProps()} className="table">
<div>
{headerGroups.map((headerGroup) => (
<div
{...headerGroup.getHeaderGroupProps({
// style: { paddingRight: '15px' },
})}
className="tr"
>
{headerGroup.headers.map((column) => (
<div {...column.getHeaderProps(headerProps)} className="th">
{column.render("Header")}
{/* Use column.getResizerProps to hook up the events correctly */}
{column.canResize && <div {...column.getResizerProps()} />}
</div>
))}
</div>
))}
</div>
<div className="tbody">
{rows.map((row) => {
prepareRow(row);
return (
<div {...row.getRowProps()} className="tr">
{row.cells.map((cell) => {
return (
<div {...cell.getCellProps(cellProps)} className="td">
{cell.render("Cell")}
</div>
);
})}
</div>
);
})}
</div>
</div>
);
}
function App() {
const columns = React.useMemo(
() => [
{
Header: "Name",
columns: [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
}
]
}
],
[]
);
const data = React.useMemo(() => makeData(20), []);
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
);
}
export default App;
This is a simple demo: https://codesandbox.io/s/gracious-leftpad-ngptb?file=/src/App.js:705-867